From fdf4e4f1859771b95585cbc87f8cd038ea2815c6 Mon Sep 17 00:00:00 2001 From: Glenn Kasten Date: Fri, 18 Jan 2013 15:31:41 -0800 Subject: Add media.log service based on NBLog Change-Id: Ie45093df6ac9a739d05c8d408fab52a9a8a27e7f --- include/media/IMediaLogService.h | 45 ++++++++++++++ media/libmedia/Android.mk | 1 + media/libmedia/IMediaLogService.cpp | 94 +++++++++++++++++++++++++++++ media/mediaserver/Android.mk | 5 ++ media/mediaserver/main_mediaserver.cpp | 105 ++++++++++++++++++++++++++++++--- services/medialog/Android.mk | 11 ++++ services/medialog/MediaLogService.cpp | 81 +++++++++++++++++++++++++ services/medialog/MediaLogService.h | 65 ++++++++++++++++++++ 8 files changed, 398 insertions(+), 9 deletions(-) create mode 100644 include/media/IMediaLogService.h create mode 100644 media/libmedia/IMediaLogService.cpp create mode 100644 services/medialog/Android.mk create mode 100644 services/medialog/MediaLogService.cpp create mode 100644 services/medialog/MediaLogService.h diff --git a/include/media/IMediaLogService.h b/include/media/IMediaLogService.h new file mode 100644 index 0000000..1f5777e --- /dev/null +++ b/include/media/IMediaLogService.h @@ -0,0 +1,45 @@ +/* + * 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. + */ + +#ifndef ANDROID_IMEDIALOGSERVICE_H +#define ANDROID_IMEDIALOGSERVICE_H + +#include +#include +#include + +namespace android { + +class IMediaLogService: public IInterface +{ +public: + DECLARE_META_INTERFACE(MediaLogService); + + virtual void registerWriter(const sp& shared, size_t size, const char *name) = 0; + virtual void unregisterWriter(const sp& shared) = 0; + +}; + +class BnMediaLogService: public BnInterface +{ +public: + virtual status_t onTransact(uint32_t code, const Parcel& data, Parcel* reply, + uint32_t flags = 0); +}; + +} // namespace android + +#endif // ANDROID_IMEDIALOGSERVICE_H diff --git a/media/libmedia/Android.mk b/media/libmedia/Android.mk index a35d562..52fa3e1 100644 --- a/media/libmedia/Android.mk +++ b/media/libmedia/Android.mk @@ -23,6 +23,7 @@ LOCAL_SRC_FILES:= \ AudioRecord.cpp \ AudioSystem.cpp \ mediaplayer.cpp \ + IMediaLogService.cpp \ IMediaPlayerService.cpp \ IMediaPlayerClient.cpp \ IMediaRecorderClient.cpp \ diff --git a/media/libmedia/IMediaLogService.cpp b/media/libmedia/IMediaLogService.cpp new file mode 100644 index 0000000..33239a7 --- /dev/null +++ b/media/libmedia/IMediaLogService.cpp @@ -0,0 +1,94 @@ +/* +** +** Copyright 2007, 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 "IMediaLogService" +//#define LOG_NDEBUG 0 + +#include +#include +#include +#include +#include + +namespace android { + +enum { + REGISTER_WRITER = IBinder::FIRST_CALL_TRANSACTION, + UNREGISTER_WRITER, +}; + +class BpMediaLogService : public BpInterface +{ +public: + BpMediaLogService(const sp& impl) + : BpInterface(impl) + { + } + + virtual void registerWriter(const sp& shared, size_t size, const char *name) { + Parcel data, reply; + data.writeInterfaceToken(IMediaLogService::getInterfaceDescriptor()); + data.writeStrongBinder(shared->asBinder()); + data.writeInt32((int32_t) size); + data.writeCString(name); + status_t status = remote()->transact(REGISTER_WRITER, data, &reply); + // FIXME ignores status + } + + virtual void unregisterWriter(const sp& shared) { + Parcel data, reply; + data.writeInterfaceToken(IMediaLogService::getInterfaceDescriptor()); + data.writeStrongBinder(shared->asBinder()); + status_t status = remote()->transact(UNREGISTER_WRITER, data, &reply); + // FIXME ignores status + } + +}; + +IMPLEMENT_META_INTERFACE(MediaLogService, "android.media.IMediaLogService"); + +// ---------------------------------------------------------------------- + +status_t BnMediaLogService::onTransact( + uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags) +{ + switch (code) { + + case REGISTER_WRITER: { + CHECK_INTERFACE(IMediaLogService, data, reply); + sp shared = interface_cast(data.readStrongBinder()); + size_t size = (size_t) data.readInt32(); + const char *name = data.readCString(); + registerWriter(shared, size, name); + return NO_ERROR; + } + + case UNREGISTER_WRITER: { + CHECK_INTERFACE(IMediaLogService, data, reply); + sp shared = interface_cast(data.readStrongBinder()); + unregisterWriter(shared); + return NO_ERROR; + } + + default: + return BBinder::onTransact(code, data, reply, flags); + } +} + +// ---------------------------------------------------------------------------- + +}; // namespace android diff --git a/media/mediaserver/Android.mk b/media/mediaserver/Android.mk index 8c3cc5e..0a0f4db 100644 --- a/media/mediaserver/Android.mk +++ b/media/mediaserver/Android.mk @@ -7,12 +7,17 @@ LOCAL_SRC_FILES:= \ LOCAL_SHARED_LIBRARIES := \ libaudioflinger \ libcameraservice \ + libmedialogservice \ + libcutils \ + libnbaio \ + libmedia \ libmediaplayerservice \ libutils \ libbinder LOCAL_C_INCLUDES := \ frameworks/av/media/libmediaplayerservice \ + frameworks/av/services/medialog \ frameworks/av/services/audioflinger \ frameworks/av/services/camera/libcameraservice diff --git a/media/mediaserver/main_mediaserver.cpp b/media/mediaserver/main_mediaserver.cpp index ddd5b84..0862952 100644 --- a/media/mediaserver/main_mediaserver.cpp +++ b/media/mediaserver/main_mediaserver.cpp @@ -18,14 +18,19 @@ #define LOG_TAG "mediaserver" //#define LOG_NDEBUG 0 +#include +#include +#include #include #include #include +#include #include // from LOCAL_C_INCLUDES #include "AudioFlinger.h" #include "CameraService.h" +#include "MediaLogService.h" #include "MediaPlayerService.h" #include "AudioPolicyService.h" @@ -34,13 +39,95 @@ using namespace android; int main(int argc, char** argv) { signal(SIGPIPE, SIG_IGN); - sp proc(ProcessState::self()); - sp sm = defaultServiceManager(); - ALOGI("ServiceManager: %p", sm.get()); - AudioFlinger::instantiate(); - MediaPlayerService::instantiate(); - CameraService::instantiate(); - AudioPolicyService::instantiate(); - ProcessState::self()->startThreadPool(); - IPCThreadState::self()->joinThreadPool(); + char value[PROPERTY_VALUE_MAX]; + bool doLog = (property_get("ro.test_harness", value, "0") > 0) && (atoi(value) == 1); + pid_t childPid; + // FIXME The advantage of making the process containing media.log service the parent process of + // the process that contains all the other real services, is that it allows us to collect more + // detailed information such as signal numbers, stop and continue, resource usage, etc. + // But it is also more complex. Consider replacing this by independent processes, and using + // binder on death notification instead. + if (doLog && (childPid = fork()) != 0) { + // media.log service + //prctl(PR_SET_NAME, (unsigned long) "media.log", 0, 0, 0); + // unfortunately ps ignores PR_SET_NAME for the main thread, so use this ugly hack + strcpy(argv[0], "media.log"); + sp proc(ProcessState::self()); + MediaLogService::instantiate(); + ProcessState::self()->startThreadPool(); + for (;;) { + siginfo_t info; + int ret = waitid(P_PID, childPid, &info, WEXITED | WSTOPPED | WCONTINUED); + if (ret == EINTR) { + continue; + } + if (ret < 0) { + break; + } + char buffer[32]; + const char *code; + switch (info.si_code) { + case CLD_EXITED: + code = "CLD_EXITED"; + break; + case CLD_KILLED: + code = "CLD_KILLED"; + break; + case CLD_DUMPED: + code = "CLD_DUMPED"; + break; + case CLD_STOPPED: + code = "CLD_STOPPED"; + break; + case CLD_TRAPPED: + code = "CLD_TRAPPED"; + break; + case CLD_CONTINUED: + code = "CLD_CONTINUED"; + break; + default: + snprintf(buffer, sizeof(buffer), "unknown (%d)", info.si_code); + code = buffer; + break; + } + struct rusage usage; + getrusage(RUSAGE_CHILDREN, &usage); + ALOG(LOG_ERROR, "media.log", "pid %d status %d code %s user %ld.%03lds sys %ld.%03lds", + info.si_pid, info.si_status, code, + usage.ru_utime.tv_sec, usage.ru_utime.tv_usec / 1000, + usage.ru_stime.tv_sec, usage.ru_stime.tv_usec / 1000); + sp sm = defaultServiceManager(); + sp binder = sm->getService(String16("media.log")); + if (binder != 0) { + Vector args; + binder->dump(-1, args); + } + switch (info.si_code) { + case CLD_EXITED: + case CLD_KILLED: + case CLD_DUMPED: { + ALOG(LOG_INFO, "media.log", "exiting"); + _exit(0); + // not reached + } + default: + break; + } + } + } else { + // all other services + if (doLog) { + prctl(PR_SET_PDEATHSIG, SIGKILL); // if parent media.log dies before me, kill me also + setpgid(0, 0); // but if I die first, don't kill my parent + } + sp proc(ProcessState::self()); + sp sm = defaultServiceManager(); + ALOGI("ServiceManager: %p", sm.get()); + AudioFlinger::instantiate(); + MediaPlayerService::instantiate(); + CameraService::instantiate(); + AudioPolicyService::instantiate(); + ProcessState::self()->startThreadPool(); + IPCThreadState::self()->joinThreadPool(); + } } diff --git a/services/medialog/Android.mk b/services/medialog/Android.mk new file mode 100644 index 0000000..559b1ed --- /dev/null +++ b/services/medialog/Android.mk @@ -0,0 +1,11 @@ +LOCAL_PATH := $(call my-dir) + +include $(CLEAR_VARS) + +LOCAL_SRC_FILES := MediaLogService.cpp + +LOCAL_SHARED_LIBRARIES := libmedia libbinder libutils libnbaio + +LOCAL_MODULE:= libmedialogservice + +include $(BUILD_SHARED_LIBRARY) diff --git a/services/medialog/MediaLogService.cpp b/services/medialog/MediaLogService.cpp new file mode 100644 index 0000000..2332b3e --- /dev/null +++ b/services/medialog/MediaLogService.cpp @@ -0,0 +1,81 @@ +/* + * 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 +#include +#include +#include +#include "MediaLogService.h" + +namespace android { + +void MediaLogService::registerWriter(const sp& shared, size_t size, const char *name) +{ + if (IPCThreadState::self()->getCallingUid() != AID_MEDIA || shared == 0 || + size < kMinSize || size > kMaxSize || name == NULL || + shared->size() < NBLog::Timeline::sharedSize(size)) { + return; + } + sp reader(new NBLog::Reader(size, shared)); + NamedReader namedReader(reader, name); + Mutex::Autolock _l(mLock); + mNamedReaders.add(namedReader); +} + +void MediaLogService::unregisterWriter(const sp& shared) +{ + if (IPCThreadState::self()->getCallingUid() != AID_MEDIA || 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++; + } + } +} + +status_t MediaLogService::dump(int fd, const Vector& args) +{ + Vector namedReaders; + { + Mutex::Autolock _l(mLock); + namedReaders = mNamedReaders; + } + for (size_t i = 0; i < namedReaders.size(); i++) { + const NamedReader& namedReader = namedReaders[i]; + if (fd >= 0) { + fdprintf(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 diff --git a/services/medialog/MediaLogService.h b/services/medialog/MediaLogService.h new file mode 100644 index 0000000..2d89a41 --- /dev/null +++ b/services/medialog/MediaLogService.h @@ -0,0 +1,65 @@ +/* + * 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. + */ + +#ifndef ANDROID_MEDIA_LOG_SERVICE_H +#define ANDROID_MEDIA_LOG_SERVICE_H + +#include +#include +#include + +namespace android { + +class MediaLogService : public BinderService, public BnMediaLogService +{ + friend class BinderService; // for MediaLogService() +public: + MediaLogService() : BnMediaLogService() { } + virtual ~MediaLogService() { } + virtual void onFirstRef() { } + + static const char* getServiceName() { return "media.log"; } + + static const size_t kMinSize = 0x100; + static const size_t kMaxSize = 0x10000; + virtual void registerWriter(const sp& shared, size_t size, const char *name); + virtual void unregisterWriter(const sp& shared); + + virtual status_t dump(int fd, const Vector& args); + virtual status_t onTransact(uint32_t code, const Parcel& data, Parcel* reply, + uint32_t flags); + +private: + Mutex mLock; + class NamedReader { + public: + NamedReader() : mReader(0) { mName[0] = '\0'; } // for Vector + NamedReader(const sp& reader, const char *name) : mReader(reader) + { strlcpy(mName, name, sizeof(mName)); } + ~NamedReader() { } + const sp& reader() const { return mReader; } + const char* name() const { return mName; } + private: + sp mReader; + static const size_t kMaxName = 32; + char mName[kMaxName]; + }; + Vector mNamedReaders; +}; + +} // namespace android + +#endif // ANDROID_MEDIA_LOG_SERVICE_H -- cgit v1.1