summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGlenn Kasten <gkasten@google.com>2013-01-18 15:31:41 -0800
committerGlenn Kasten <gkasten@google.com>2013-01-25 15:12:14 -0800
commitfdf4e4f1859771b95585cbc87f8cd038ea2815c6 (patch)
tree7bbc12a9d0e9c7ad29346b04b26c55d390a0b032
parent10eb4b33545a58e4b09249c30c100bc7b992250a (diff)
downloadframeworks_av-fdf4e4f1859771b95585cbc87f8cd038ea2815c6.zip
frameworks_av-fdf4e4f1859771b95585cbc87f8cd038ea2815c6.tar.gz
frameworks_av-fdf4e4f1859771b95585cbc87f8cd038ea2815c6.tar.bz2
Add media.log service based on NBLog
Change-Id: Ie45093df6ac9a739d05c8d408fab52a9a8a27e7f
-rw-r--r--include/media/IMediaLogService.h45
-rw-r--r--media/libmedia/Android.mk1
-rw-r--r--media/libmedia/IMediaLogService.cpp94
-rw-r--r--media/mediaserver/Android.mk5
-rw-r--r--media/mediaserver/main_mediaserver.cpp105
-rw-r--r--services/medialog/Android.mk11
-rw-r--r--services/medialog/MediaLogService.cpp81
-rw-r--r--services/medialog/MediaLogService.h65
8 files changed, 398 insertions, 9 deletions
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 <binder/IInterface.h>
+#include <binder/IMemory.h>
+#include <binder/Parcel.h>
+
+namespace android {
+
+class IMediaLogService: public IInterface
+{
+public:
+ DECLARE_META_INTERFACE(MediaLogService);
+
+ virtual void registerWriter(const sp<IMemory>& shared, size_t size, const char *name) = 0;
+ virtual void unregisterWriter(const sp<IMemory>& shared) = 0;
+
+};
+
+class BnMediaLogService: public BnInterface<IMediaLogService>
+{
+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 <utils/Log.h>
+#include <stdint.h>
+#include <sys/types.h>
+#include <binder/Parcel.h>
+#include <media/IMediaLogService.h>
+
+namespace android {
+
+enum {
+ REGISTER_WRITER = IBinder::FIRST_CALL_TRANSACTION,
+ UNREGISTER_WRITER,
+};
+
+class BpMediaLogService : public BpInterface<IMediaLogService>
+{
+public:
+ BpMediaLogService(const sp<IBinder>& impl)
+ : BpInterface<IMediaLogService>(impl)
+ {
+ }
+
+ virtual void registerWriter(const sp<IMemory>& 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<IMemory>& 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<IMemory> shared = interface_cast<IMemory>(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<IMemory> shared = interface_cast<IMemory>(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 <fcntl.h>
+#include <sys/prctl.h>
+#include <sys/wait.h>
#include <binder/IPCThreadState.h>
#include <binder/ProcessState.h>
#include <binder/IServiceManager.h>
+#include <cutils/properties.h>
#include <utils/Log.h>
// 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<ProcessState> proc(ProcessState::self());
- sp<IServiceManager> 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<ProcessState> 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<IServiceManager> sm = defaultServiceManager();
+ sp<IBinder> binder = sm->getService(String16("media.log"));
+ if (binder != 0) {
+ Vector<String16> 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<ProcessState> proc(ProcessState::self());
+ sp<IServiceManager> 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 <sys/mman.h>
+#include <utils/Log.h>
+#include <media/nbaio/NBLog.h>
+#include <private/android_filesystem_config.h>
+#include "MediaLogService.h"
+
+namespace android {
+
+void MediaLogService::registerWriter(const sp<IMemory>& 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<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_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<String16>& args)
+{
+ Vector<NamedReader> 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 <binder/BinderService.h>
+#include <media/IMediaLogService.h>
+#include <media/nbaio/NBLog.h>
+
+namespace android {
+
+class MediaLogService : public BinderService<MediaLogService>, public BnMediaLogService
+{
+ friend class BinderService<MediaLogService>; // 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<IMemory>& shared, size_t size, const char *name);
+ virtual void unregisterWriter(const sp<IMemory>& shared);
+
+ virtual status_t dump(int fd, const Vector<String16>& 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<NBLog::Reader>& reader, const char *name) : mReader(reader)
+ { strlcpy(mName, name, sizeof(mName)); }
+ ~NamedReader() { }
+ const sp<NBLog::Reader>& reader() const { return mReader; }
+ const char* name() const { return mName; }
+ private:
+ sp<NBLog::Reader> mReader;
+ static const size_t kMaxName = 32;
+ char mName[kMaxName];
+ };
+ Vector<NamedReader> mNamedReaders;
+};
+
+} // namespace android
+
+#endif // ANDROID_MEDIA_LOG_SERVICE_H