/*
* Copyright (C) 2013 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#define LOG_TAG "MediaLog"
//#define LOG_NDEBUG 0
#include <sys/mman.h>
#include <utils/Log.h>
#include <binder/PermissionCache.h>
#include <media/nbaio/NBLog.h>
#include <private/android_filesystem_config.h>
#include "MediaLogService.h"
namespace android {
static const char kDeadlockedString[] = "MediaLogService may be deadlocked\n";
void MediaLogService::registerWriter(const sp<IMemory>& shared, size_t size, const char *name)
{
if (IPCThreadState::self()->getCallingUid() != AID_AUDIOSERVER || shared == 0 ||
size < kMinSize || size > kMaxSize || name == NULL ||
shared->size() < NBLog::Timeline::sharedSize(size)) {
return;
}
sp<NBLog::Reader> reader(new NBLog::Reader(size, shared));
NamedReader namedReader(reader, name);
Mutex::Autolock _l(mLock);
mNamedReaders.add(namedReader);
}
void MediaLogService::unregisterWriter(const sp<IMemory>& shared)
{
if (IPCThreadState::self()->getCallingUid() != AID_AUDIOSERVER || shared == 0) {
return;
}
Mutex::Autolock _l(mLock);
for (size_t i = 0; i < mNamedReaders.size(); ) {
if (mNamedReaders[i].reader()->isIMemory(shared)) {
mNamedReaders.removeAt(i);
} else {
i++;
}
}
}
bool MediaLogService::dumpTryLock(Mutex& mutex)
{
bool locked = false;
for (int i = 0; i < kDumpLockRetries; ++i) {
if (mutex.tryLock() == NO_ERROR) {
locked = true;
break;
}
usleep(kDumpLockSleepUs);
}
return locked;
}
status_t MediaLogService::dump(int fd, const Vector<String16>& args __unused)
{
// FIXME merge with similar but not identical code at services/audioflinger/ServiceUtilities.cpp
static const String16 sDump("android.permission.DUMP");
if (!(IPCThreadState::self()->getCallingUid() == AID_AUDIOSERVER ||
PermissionCache::checkCallingPermission(sDump))) {
dprintf(fd, "Permission Denial: can't dump media.log from pid=%d, uid=%d\n",
IPCThreadState::self()->getCallingPid(),
IPCThreadState::self()->getCallingUid());
return NO_ERROR;
}
Vector<NamedReader> namedReaders;
{
bool locked = dumpTryLock(mLock);
// failed to lock - MediaLogService is probably deadlocked
if (!locked) {
String8 result(kDeadlockedString);
if (fd >= 0) {
write(fd, result.string(), result.size());
} else {
ALOGW("%s:", result.string());
}
return NO_ERROR;
}
namedReaders = mNamedReaders;
mLock.unlock();
}
for (size_t i = 0; i < namedReaders.size(); i++) {
const NamedReader& namedReader = namedReaders[i];
if (fd >= 0) {
dprintf(fd, "\n%s:\n", namedReader.name());
} else {
ALOGI("%s:", namedReader.name());
}
namedReader.reader()->dump(fd, 0 /*indent*/);
}
return NO_ERROR;
}
status_t MediaLogService::onTransact(uint32_t code, const Parcel& data, Parcel* reply,
uint32_t flags)
{
return BnMediaLogService::onTransact(code, data, reply, flags);
}
} // namespace android