Home | History | Annotate | Download | only in medialog
      1 /*
      2  * Copyright (C) 2013 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 #define LOG_TAG "MediaLog"
     18 //#define LOG_NDEBUG 0
     19 
     20 #include <sys/mman.h>
     21 #include <utils/Log.h>
     22 #include <binder/PermissionCache.h>
     23 #include <media/nblog/Merger.h>
     24 #include <media/nblog/NBLog.h>
     25 #include <mediautils/ServiceUtilities.h>
     26 #include "MediaLogService.h"
     27 
     28 namespace android {
     29 
     30 static const char kDeadlockedString[] = "MediaLogService may be deadlocked\n";
     31 
     32 // mMerger, mMergeReader, and mMergeThread all point to the same location in memory
     33 // mMergerShared. This is the local memory FIFO containing data merged from all
     34 // individual thread FIFOs in shared memory. mMergeThread is used to periodically
     35 // call NBLog::Merger::merge() to collect the data and write it to the FIFO, and call
     36 // NBLog::MergeReader::getAndProcessSnapshot to process the merged data.
     37 MediaLogService::MediaLogService() :
     38     BnMediaLogService(),
     39     mMergerShared((NBLog::Shared*) malloc(NBLog::Timeline::sharedSize(kMergeBufferSize))),
     40     mMerger(mMergerShared, kMergeBufferSize),
     41     mMergeReader(mMergerShared, kMergeBufferSize, mMerger),
     42     mMergeThread(new NBLog::MergeThread(mMerger, mMergeReader))
     43 {
     44     mMergeThread->run("MergeThread");
     45 }
     46 
     47 MediaLogService::~MediaLogService()
     48 {
     49     mMergeThread->requestExit();
     50     mMergeThread->setTimeoutUs(0);
     51     mMergeThread->join();
     52     free(mMergerShared);
     53 }
     54 
     55 void MediaLogService::registerWriter(const sp<IMemory>& shared, size_t size, const char *name)
     56 {
     57     if (!isAudioServerOrMediaServerUid(IPCThreadState::self()->getCallingUid()) || shared == 0 ||
     58             size < kMinSize || size > kMaxSize || name == NULL ||
     59             shared->size() < NBLog::Timeline::sharedSize(size)) {
     60         return;
     61     }
     62     sp<NBLog::Reader> reader(new NBLog::Reader(shared, size, name)); // Reader handled by merger
     63     sp<NBLog::DumpReader> dumpReader(new NBLog::DumpReader(shared, size, name)); // for dumpsys
     64     Mutex::Autolock _l(mLock);
     65     mDumpReaders.add(dumpReader);
     66     mMerger.addReader(reader);
     67 }
     68 
     69 void MediaLogService::unregisterWriter(const sp<IMemory>& shared)
     70 {
     71     if (!isAudioServerOrMediaServerUid(IPCThreadState::self()->getCallingUid()) || shared == 0) {
     72         return;
     73     }
     74     Mutex::Autolock _l(mLock);
     75     for (size_t i = 0; i < mDumpReaders.size(); ) {
     76         if (mDumpReaders[i]->isIMemory(shared)) {
     77             mDumpReaders.removeAt(i);
     78             // TODO mMerger.removeReaders(shared)
     79         } else {
     80             i++;
     81         }
     82     }
     83 }
     84 
     85 bool MediaLogService::dumpTryLock(Mutex& mutex)
     86 {
     87     bool locked = false;
     88     for (int i = 0; i < kDumpLockRetries; ++i) {
     89         if (mutex.tryLock() == NO_ERROR) {
     90             locked = true;
     91             break;
     92         }
     93         usleep(kDumpLockSleepUs);
     94     }
     95     return locked;
     96 }
     97 
     98 status_t MediaLogService::dump(int fd, const Vector<String16>& args __unused)
     99 {
    100     if (!(isAudioServerOrMediaServerUid(IPCThreadState::self()->getCallingUid())
    101             || dumpAllowed())) {
    102         dprintf(fd, "Permission Denial: can't dump media.log from pid=%d, uid=%d\n",
    103                 IPCThreadState::self()->getCallingPid(),
    104                 IPCThreadState::self()->getCallingUid());
    105         return NO_ERROR;
    106     }
    107 
    108     if (args.size() > 0) {
    109         const String8 arg0(args[0]);
    110         if (!strcmp(arg0.string(), "-r")) {
    111             // needed because mReaders is protected by mLock
    112             bool locked = dumpTryLock(mLock);
    113 
    114             // failed to lock - MediaLogService is probably deadlocked
    115             if (!locked) {
    116                 String8 result(kDeadlockedString);
    117                 if (fd >= 0) {
    118                     write(fd, result.string(), result.size());
    119                 } else {
    120                     ALOGW("%s:", result.string());
    121                 }
    122                 return NO_ERROR;
    123             }
    124 
    125             for (const auto &dumpReader : mDumpReaders) {
    126                 if (fd >= 0) {
    127                     dprintf(fd, "\n%s:\n", dumpReader->name().c_str());
    128                     dumpReader->dump(fd, 0 /*indent*/);
    129                 } else {
    130                     ALOGI("%s:", dumpReader->name().c_str());
    131                 }
    132             }
    133             mLock.unlock();
    134         } else {
    135             mMergeReader.dump(fd, args);
    136         }
    137     }
    138     return NO_ERROR;
    139 }
    140 
    141 status_t MediaLogService::onTransact(uint32_t code, const Parcel& data, Parcel* reply,
    142         uint32_t flags)
    143 {
    144     return BnMediaLogService::onTransact(code, data, reply, flags);
    145 }
    146 
    147 void MediaLogService::requestMergeWakeup() {
    148     mMergeThread->wakeup();
    149 }
    150 
    151 }   // namespace android
    152