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/NBLog.h> 24#include <private/android_filesystem_config.h> 25#include "MediaLogService.h" 26 27namespace android { 28 29static const char kDeadlockedString[] = "MediaLogService may be deadlocked\n"; 30 31// mMerger, mMergeReader, and mMergeThread all point to the same location in memory 32// mMergerShared. This is the local memory FIFO containing data merged from all 33// individual thread FIFOs in shared memory. mMergeThread is used to periodically 34// call NBLog::Merger::merge() to collect the data and write it to the FIFO, and call 35// NBLog::MergeReader::getAndProcessSnapshot to process the merged data. 36MediaLogService::MediaLogService() : 37 BnMediaLogService(), 38 mMergerShared((NBLog::Shared*) malloc(NBLog::Timeline::sharedSize(kMergeBufferSize))), 39 mMerger(mMergerShared, kMergeBufferSize), 40 mMergeReader(mMergerShared, kMergeBufferSize, mMerger), 41 mMergeThread(new NBLog::MergeThread(mMerger, mMergeReader)) 42{ 43 mMergeThread->run("MergeThread"); 44} 45 46MediaLogService::~MediaLogService() 47{ 48 mMergeThread->requestExit(); 49 mMergeThread->setTimeoutUs(0); 50 mMergeThread->join(); 51 free(mMergerShared); 52} 53 54void MediaLogService::registerWriter(const sp<IMemory>& shared, size_t size, const char *name) 55{ 56 if (IPCThreadState::self()->getCallingUid() != AID_AUDIOSERVER || shared == 0 || 57 size < kMinSize || size > kMaxSize || name == NULL || 58 shared->size() < NBLog::Timeline::sharedSize(size)) { 59 return; 60 } 61 sp<NBLog::Reader> reader(new NBLog::Reader(shared, size)); 62 NBLog::NamedReader namedReader(reader, name); 63 Mutex::Autolock _l(mLock); 64 mNamedReaders.add(namedReader); 65 mMerger.addReader(namedReader); 66} 67 68void MediaLogService::unregisterWriter(const sp<IMemory>& shared) 69{ 70 if (IPCThreadState::self()->getCallingUid() != AID_AUDIOSERVER || shared == 0) { 71 return; 72 } 73 Mutex::Autolock _l(mLock); 74 for (size_t i = 0; i < mNamedReaders.size(); ) { 75 if (mNamedReaders[i].reader()->isIMemory(shared)) { 76 mNamedReaders.removeAt(i); 77 } else { 78 i++; 79 } 80 } 81} 82 83bool MediaLogService::dumpTryLock(Mutex& mutex) 84{ 85 bool locked = false; 86 for (int i = 0; i < kDumpLockRetries; ++i) { 87 if (mutex.tryLock() == NO_ERROR) { 88 locked = true; 89 break; 90 } 91 usleep(kDumpLockSleepUs); 92 } 93 return locked; 94} 95 96status_t MediaLogService::dump(int fd, const Vector<String16>& args __unused) 97{ 98 // FIXME merge with similar but not identical code at services/audioflinger/ServiceUtilities.cpp 99 static const String16 sDump("android.permission.DUMP"); 100 if (!(IPCThreadState::self()->getCallingUid() == AID_AUDIOSERVER || 101 PermissionCache::checkCallingPermission(sDump))) { 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 mNamedReaders 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 // TODO should we instead proceed to mMergeReader.dump? does it need lock? 123 return NO_ERROR; 124 } 125 126 for (const auto& namedReader : mNamedReaders) { 127 if (fd >= 0) { 128 dprintf(fd, "\n%s:\n", namedReader.name()); 129 } else { 130 ALOGI("%s:", namedReader.name()); 131 } 132 } 133 mLock.unlock(); 134 } 135 } 136 mMergeReader.dump(fd); 137 return NO_ERROR; 138} 139 140status_t MediaLogService::onTransact(uint32_t code, const Parcel& data, Parcel* reply, 141 uint32_t flags) 142{ 143 return BnMediaLogService::onTransact(code, data, reply, flags); 144} 145 146void MediaLogService::requestMergeWakeup() { 147 mMergeThread->wakeup(); 148} 149 150} // namespace android 151