summaryrefslogtreecommitdiffstats
path: root/cmds/runtime
diff options
context:
space:
mode:
authorThe Android Open Source Project <initial-contribution@android.com>2009-03-03 19:31:44 -0800
committerThe Android Open Source Project <initial-contribution@android.com>2009-03-03 19:31:44 -0800
commit9066cfe9886ac131c34d59ed0e2d287b0e3c0087 (patch)
treed88beb88001f2482911e3d28e43833b50e4b4e97 /cmds/runtime
parentd83a98f4ce9cfa908f5c54bbd70f03eec07e7553 (diff)
downloadframeworks_base-9066cfe9886ac131c34d59ed0e2d287b0e3c0087.zip
frameworks_base-9066cfe9886ac131c34d59ed0e2d287b0e3c0087.tar.gz
frameworks_base-9066cfe9886ac131c34d59ed0e2d287b0e3c0087.tar.bz2
auto import from //depot/cupcake/@135843
Diffstat (limited to 'cmds/runtime')
-rw-r--r--cmds/runtime/Android.mk29
-rw-r--r--cmds/runtime/MODULE_LICENSE_APACHE20
-rw-r--r--cmds/runtime/NOTICE190
-rw-r--r--cmds/runtime/ServiceManager.cpp74
-rw-r--r--cmds/runtime/ServiceManager.h38
-rw-r--r--cmds/runtime/SignalHandler.cpp249
-rw-r--r--cmds/runtime/SignalHandler.h137
-rw-r--r--cmds/runtime/main_runtime.cpp514
8 files changed, 1231 insertions, 0 deletions
diff --git a/cmds/runtime/Android.mk b/cmds/runtime/Android.mk
new file mode 100644
index 0000000..521eb2b
--- /dev/null
+++ b/cmds/runtime/Android.mk
@@ -0,0 +1,29 @@
+ifeq ($(TARGET_SIMULATOR),true)
+
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES:= \
+ ServiceManager.cpp \
+ SignalHandler.cpp \
+ main_runtime.cpp
+
+LOCAL_SHARED_LIBRARIES := \
+ libutils \
+ libandroid_runtime \
+ libcutils \
+ libui \
+ libsystem_server \
+ libhardware_legacy
+
+LOCAL_C_INCLUDES := \
+ $(JNI_H_INCLUDE)
+
+ifeq ($(TARGET_OS),linux)
+ LOCAL_CFLAGS += -DXP_UNIX
+endif
+
+LOCAL_MODULE:= runtime
+
+include $(BUILD_EXECUTABLE)
+endif
diff --git a/cmds/runtime/MODULE_LICENSE_APACHE2 b/cmds/runtime/MODULE_LICENSE_APACHE2
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/cmds/runtime/MODULE_LICENSE_APACHE2
diff --git a/cmds/runtime/NOTICE b/cmds/runtime/NOTICE
new file mode 100644
index 0000000..c5b1efa
--- /dev/null
+++ b/cmds/runtime/NOTICE
@@ -0,0 +1,190 @@
+
+ Copyright (c) 2005-2008, 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.
+
+ 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.
+
+
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+ 1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+ 2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+ 3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+ 4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+ 6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+ 7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+ 8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+ 9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+ END OF TERMS AND CONDITIONS
+
diff --git a/cmds/runtime/ServiceManager.cpp b/cmds/runtime/ServiceManager.cpp
new file mode 100644
index 0000000..758a95c
--- /dev/null
+++ b/cmds/runtime/ServiceManager.cpp
@@ -0,0 +1,74 @@
+//
+// Copyright 2005 The Android Open Source Project
+//
+
+#define LOG_TAG "ServiceManager"
+
+#include "ServiceManager.h"
+#include "SignalHandler.h"
+
+#include <utils/Debug.h>
+#include <utils/Log.h>
+#include <utils/Parcel.h>
+#include <utils/String8.h>
+#include <utils/ProcessState.h>
+
+#include <private/utils/Static.h>
+
+#include <ctype.h>
+#include <errno.h>
+#include <limits.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/stat.h>
+
+namespace android {
+
+BServiceManager::BServiceManager()
+{
+}
+
+sp<IBinder> BServiceManager::getService(const String16& name) const
+{
+ AutoMutex _l(mLock);
+ ssize_t i = mServices.indexOfKey(name);
+ LOGV("ServiceManager: getService(%s) -> %d\n", String8(name).string(), i);
+ if (i >= 0) return mServices.valueAt(i);
+ return NULL;
+}
+
+sp<IBinder> BServiceManager::checkService(const String16& name) const
+{
+ AutoMutex _l(mLock);
+ ssize_t i = mServices.indexOfKey(name);
+ LOGV("ServiceManager: getService(%s) -> %d\n", String8(name).string(), i);
+ if (i >= 0) return mServices.valueAt(i);
+ return NULL;
+}
+
+status_t BServiceManager::addService(const String16& name, const sp<IBinder>& service)
+{
+ AutoMutex _l(mLock);
+ LOGI("ServiceManager: addService(%s, %p)\n", String8(name).string(), service.get());
+ const ssize_t res = mServices.add(name, service);
+ if (res >= NO_ERROR) {
+ mChanged.broadcast();
+ return NO_ERROR;
+ }
+ return res;
+}
+
+Vector<String16> BServiceManager::listServices()
+{
+ Vector<String16> res;
+
+ AutoMutex _l(mLock);
+ const size_t N = mServices.size();
+ for (size_t i=0; i<N; i++) {
+ res.add(mServices.keyAt(i));
+ }
+
+ return res;
+}
+
+}; // namespace android
diff --git a/cmds/runtime/ServiceManager.h b/cmds/runtime/ServiceManager.h
new file mode 100644
index 0000000..d09cec8
--- /dev/null
+++ b/cmds/runtime/ServiceManager.h
@@ -0,0 +1,38 @@
+//
+// Copyright 2005 The Android Open Source Project
+//
+#ifndef ANDROID_SERVICE_MANAGER_H
+#define ANDROID_SERVICE_MANAGER_H
+
+#include <utils/IServiceManager.h>
+#include <utils/KeyedVector.h>
+#include <utils/threads.h>
+
+namespace android {
+
+// ----------------------------------------------------------------------
+
+class BServiceManager : public BnServiceManager
+{
+public:
+ BServiceManager();
+
+ virtual sp<IBinder> getService( const String16& name) const;
+ virtual sp<IBinder> checkService( const String16& name) const;
+ virtual status_t addService( const String16& name,
+ const sp<IBinder>& service);
+ virtual Vector<String16> listServices();
+
+
+private:
+ mutable Mutex mLock;
+ mutable Condition mChanged;
+ sp<IPermissionController> mPermissionController;
+ KeyedVector<String16, sp<IBinder> > mServices;
+};
+
+// ----------------------------------------------------------------------
+
+}; // namespace android
+
+#endif // ANDROID_SERVICE_MANAGER_H
diff --git a/cmds/runtime/SignalHandler.cpp b/cmds/runtime/SignalHandler.cpp
new file mode 100644
index 0000000..cccaabf
--- /dev/null
+++ b/cmds/runtime/SignalHandler.cpp
@@ -0,0 +1,249 @@
+//
+// Copyright 2005 The Android Open Source Project
+//
+
+#define LOG_TAG "SignalHandler"
+
+#include "SignalHandler.h"
+
+#include <utils/Atomic.h>
+#include <utils/Debug.h>
+#include <utils/Log.h>
+
+#include <errno.h>
+#include <sys/wait.h>
+#include <unistd.h>
+
+namespace android {
+
+class SignalHandler::ProcessThread : public Thread
+{
+public:
+ ProcessThread(SignalHandler& sh)
+ : Thread(false)
+ , mOwner(sh)
+ {
+ }
+
+ virtual bool threadLoop()
+ {
+ char buffer[32];
+ read(mOwner.mAvailMsg[0], buffer, sizeof(buffer));
+
+ LOGV("Signal command processing thread woke up!");
+
+ if (mOwner.mLostCommands) {
+ LOGE("Lost %d signals!", mOwner.mLostCommands);
+ mOwner.mLostCommands = 0;
+ }
+
+ int cur;
+ while ((cur=mOwner.mCommandBottom) != mOwner.mCommandTop) {
+ if (mOwner.mCommands[cur].filled == 0) {
+ LOGV("Command at %d is not yet filled", cur);
+ break;
+ }
+
+ LOGV("Processing command at %d, top is %d",
+ cur, mOwner.mCommandTop);
+ processCommand(mOwner.mCommands[cur]);
+ mOwner.mCommands[cur].filled = 0;
+
+ int next = mOwner.mCommandBottom+1;
+ if (next >= COMMAND_QUEUE_SIZE) {
+ next = 0;
+ }
+
+ mOwner.mCommandBottom = next;
+ }
+
+ return true;
+ }
+
+ void processCommand(const CommandEntry& entry)
+ {
+ switch (entry.signum) {
+ case SIGCHLD: {
+ mOwner.mLock.lock();
+ ssize_t i = mOwner.mChildHandlers.indexOfKey(entry.info.si_pid);
+ ChildHandler ch;
+ if (i >= 0) {
+ ch = mOwner.mChildHandlers.valueAt(i);
+ mOwner.mChildHandlers.removeItemsAt(i);
+ }
+ mOwner.mLock.unlock();
+
+ LOGD("SIGCHLD: pid=%d, handle index=%d", entry.info.si_pid, i);
+
+ if (i >= 0) {
+ int res = waitpid(entry.info.si_pid, NULL, WNOHANG);
+ LOGW_IF(res == 0,
+ "Received SIGCHLD, but pid %d is not yet stopped",
+ entry.info.si_pid);
+ if (ch.handler) {
+ ch.handler(entry.info.si_pid, ch.userData);
+ }
+ } else {
+ LOGW("Unhandled SIGCHLD for pid %d", entry.info.si_pid);
+ }
+ } break;
+ }
+ }
+
+ SignalHandler& mOwner;
+};
+
+
+Mutex SignalHandler::mInstanceLock;
+SignalHandler* SignalHandler::mInstance = NULL;
+
+status_t SignalHandler::setChildHandler(pid_t childPid,
+ int tag,
+ child_callback_t handler,
+ void* userData)
+{
+ SignalHandler* const self = getInstance();
+
+ self->mLock.lock();
+
+ // First make sure this child hasn't already exited.
+ pid_t res = waitpid(childPid, NULL, WNOHANG);
+ if (res != 0) {
+ if (res < 0) {
+ LOGW("setChildHandler waitpid of %d failed: %d (%s)",
+ childPid, res, strerror(errno));
+ } else {
+ LOGW("setChildHandler waitpid of %d said %d already dead",
+ childPid, res);
+ }
+
+ // Some kind of error... just handle the exit now.
+ self->mLock.unlock();
+
+ if (handler) {
+ handler(childPid, userData);
+ }
+
+ // Return an error code -- 0 means it already exited.
+ return (status_t)res;
+ }
+
+ ChildHandler entry;
+ entry.childPid = childPid;
+ entry.tag = tag;
+ entry.handler = handler;
+ entry.userData = userData;
+
+ // Note: this replaces an existing entry for this pid, if there already
+ // is one. This is the required behavior.
+ LOGD("setChildHandler adding pid %d, tag %d, handler %p, data %p",
+ childPid, tag, handler, userData);
+ self->mChildHandlers.add(childPid, entry);
+
+ self->mLock.unlock();
+
+ return NO_ERROR;
+}
+
+void SignalHandler::killAllChildren(int tag)
+{
+ SignalHandler* const self = getInstance();
+
+ AutoMutex _l (self->mLock);
+ const size_t N = self->mChildHandlers.size();
+ for (size_t i=0; i<N; i++) {
+ const ChildHandler& ch(self->mChildHandlers.valueAt(i));
+ if (tag == 0 || ch.tag == tag) {
+ const pid_t pid = ch.childPid;
+ LOGI("Killing child %d (tag %d)\n", pid, ch.tag);
+ kill(pid, SIGKILL);
+ }
+ }
+}
+
+SignalHandler::SignalHandler()
+ : mCommandTop(0)
+ , mCommandBottom(0)
+ , mLostCommands(0)
+{
+ memset(mCommands, 0, sizeof(mCommands));
+
+ int res = pipe(mAvailMsg);
+ LOGE_IF(res != 0, "Unable to create signal handler pipe: %s", strerror(errno));
+
+ mProcessThread = new ProcessThread(*this);
+ mProcessThread->run("SignalHandler", PRIORITY_HIGHEST);
+
+ struct sigaction sa;
+ memset(&sa, 0, sizeof(sa));
+ sa.sa_sigaction = sigAction;
+ sa.sa_flags = SA_NOCLDSTOP|SA_SIGINFO;
+ sigaction(SIGCHLD, &sa, NULL);
+}
+
+SignalHandler::~SignalHandler()
+{
+}
+
+SignalHandler* SignalHandler::getInstance()
+{
+ AutoMutex _l(mInstanceLock);
+ if (mInstance == NULL) {
+ mInstance = new SignalHandler();
+ }
+ return mInstance;
+}
+
+void SignalHandler::sigAction(int signum, siginfo_t* info, void*)
+{
+ static const char wakeupMsg[1] = { 0xff };
+
+ // If our signal handler is being called, then we know we have
+ // already initialized the SignalHandler class and thus mInstance
+ // is valid.
+ SignalHandler* const self = mInstance;
+
+ // XXX This is not safe!
+ #if 0
+ LOGV("Signal %d: signo=%d, errno=%d, code=%d, pid=%d\n",
+ signum,
+ info->si_signo, info->si_errno, info->si_code,
+ info->si_pid);
+ #endif
+
+ int32_t oldTop, newTop;
+
+ // Find the next command slot...
+ do {
+ oldTop = self->mCommandTop;
+
+ newTop = oldTop + 1;
+ if (newTop >= COMMAND_QUEUE_SIZE) {
+ newTop = 0;
+ }
+
+ if (newTop == self->mCommandBottom) {
+ // The buffer is filled up! Ouch!
+ // XXX This is not safe!
+ #if 0
+ LOGE("Command buffer overflow! newTop=%d\n", newTop);
+ #endif
+ android_atomic_add(1, &self->mLostCommands);
+ write(self->mAvailMsg[1], wakeupMsg, sizeof(wakeupMsg));
+ return;
+ }
+ } while(android_atomic_cmpxchg(oldTop, newTop, &(self->mCommandTop)));
+
+ // Fill in the command data...
+ self->mCommands[oldTop].signum = signum;
+ self->mCommands[oldTop].info = *info;
+
+ // And now make this command available.
+ self->mCommands[oldTop].filled = 1;
+
+ // Wake up the processing thread.
+ write(self->mAvailMsg[1], wakeupMsg, sizeof(wakeupMsg));
+}
+
+}; // namespace android
+
diff --git a/cmds/runtime/SignalHandler.h b/cmds/runtime/SignalHandler.h
new file mode 100644
index 0000000..7f4ef8e
--- /dev/null
+++ b/cmds/runtime/SignalHandler.h
@@ -0,0 +1,137 @@
+//
+// Copyright 2005 The Android Open Source Project
+//
+#ifndef ANDROID_SIGNAL_HANDLER_H
+#define ANDROID_SIGNAL_HANDLER_H
+
+#include <utils/KeyedVector.h>
+#include <utils/threads.h>
+
+#include <signal.h>
+
+namespace android {
+
+// ----------------------------------------------------------------------
+
+enum {
+ DEFAULT_PROCESS_TAG = 1
+};
+
+class SignalHandler
+{
+public:
+ typedef void (*child_callback_t)(pid_t child, void* userData);
+
+ /**
+ * Set a handler for when a child process exits. By calling
+ * this, a waitpid() will be done when the child exits to remove
+ * it from the zombie state. You can also optionally specify a
+ * handler to be called when the child exits.
+ *
+ * If there is already a handler for this child process, it is
+ * replaced by this new handler. In this case the old handler's
+ * function is not called.
+ *
+ * @param childPid Process ID of child to watch.
+ * @param childTag User-defined tag for this child. Must be
+ * greater than zero.
+ * @param handler If non-NULL, this will be called when the
+ * child exits. It may be called in either a
+ * separate signal handling thread, or
+ * immediately if the child has already exited.
+ * @param userData Propageted as-is to handler.
+ *
+ * @return status_t NO_ERROR if all is well.
+ */
+ static status_t setChildHandler(pid_t childPid,
+ int childTag = DEFAULT_PROCESS_TAG,
+ child_callback_t handler = NULL,
+ void* userData = NULL);
+
+ /**
+ * Kill all of the child processes for which we have a waiting
+ * handler, whose tag is the given value. If tag is 0, all
+ * children are killed.
+ *
+ * @param tag
+ */
+ static void killAllChildren(int tag = 0);
+
+private:
+ SignalHandler();
+ ~SignalHandler();
+
+ static SignalHandler* getInstance();
+
+ static void sigAction(int, siginfo_t*, void*);
+
+ // --------------------------------------------------
+ // Shared state... all of this is protected by mLock.
+ // --------------------------------------------------
+
+ mutable Mutex mLock;
+
+ struct ChildHandler
+ {
+ pid_t childPid;
+ int tag;
+ child_callback_t handler;
+ void* userData;
+ };
+ KeyedVector<pid_t, ChildHandler> mChildHandlers;
+
+ // --------------------------------------------------
+ // Commmand queue... data is inserted by the signal
+ // handler using atomic ops, and retrieved by the
+ // signal processing thread. Because these are touched
+ // by the signal handler, no lock is used.
+ // --------------------------------------------------
+
+ enum {
+ COMMAND_QUEUE_SIZE = 64
+ };
+ struct CommandEntry
+ {
+ int filled;
+ int signum;
+ siginfo_t info;
+ };
+
+ // The top of the queue. This is incremented atomically by the
+ // signal handler before placing a command in the queue.
+ volatile int32_t mCommandTop;
+
+ // The bottom of the queue. Only modified by the processing
+ // thread; the signal handler reads it only to determine if the
+ // queue is full.
+ int32_t mCommandBottom;
+
+ // Incremented each time we receive a signal and don't have room
+ // for it on the command queue.
+ volatile int32_t mLostCommands;
+
+ // The command processing thread.
+ class ProcessThread;
+ sp<Thread> mProcessThread;
+
+ // Pipe used to tell command processing thread when new commands.
+ // are available. The thread blocks on the read end, the signal
+ // handler writes when it enqueues new commands.
+ int mAvailMsg[2];
+
+ // The commands.
+ CommandEntry mCommands[COMMAND_QUEUE_SIZE];
+
+ // --------------------------------------------------
+ // Singleton.
+ // --------------------------------------------------
+
+ static Mutex mInstanceLock;
+ static SignalHandler* mInstance;
+};
+
+// ----------------------------------------------------------------------
+
+}; // namespace android
+
+#endif // ANDROID_SIGNAL_HANDLER_H
diff --git a/cmds/runtime/main_runtime.cpp b/cmds/runtime/main_runtime.cpp
new file mode 100644
index 0000000..1531a9e
--- /dev/null
+++ b/cmds/runtime/main_runtime.cpp
@@ -0,0 +1,514 @@
+//
+// Copyright 2005 The Android Open Source Project
+//
+// Main entry point for runtime.
+//
+
+#include "ServiceManager.h"
+#include "SignalHandler.h"
+
+#include <utils.h>
+#include <utils/IPCThreadState.h>
+#include <utils/ProcessState.h>
+#include <utils/Log.h>
+#include <cutils/zygote.h>
+
+#include <cutils/properties.h>
+
+#include <private/utils/Static.h>
+
+#include <ui/ISurfaceComposer.h>
+
+#include <android_runtime/AndroidRuntime.h>
+
+#include <stdlib.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <string.h>
+#include <getopt.h>
+#include <signal.h>
+#include <errno.h>
+#include <sys/stat.h>
+#include <linux/capability.h>
+#include <linux/ioctl.h>
+#ifdef HAVE_ANDROID_OS
+# include <linux/android_alarm.h>
+#endif
+
+#undef LOG_TAG
+#define LOG_TAG "runtime"
+
+static const char* ZYGOTE_ARGV[] = {
+ "--setuid=1000",
+ "--setgid=1000",
+ "--setgroups=1001,1002,1003,1004,1005,1006,1007,1008,1009,1010,3001,3002,3003",
+ /* CAP_SYS_TTY_CONFIG & CAP_SYS_RESOURCE & CAP_NET_BROADCAST &
+ * CAP_NET_ADMIN & CAP_NET_RAW & CAP_NET_BIND_SERVICE & CAP_KILL &
+ * CAP_SYS_BOOT
+ */
+ "--capabilities=88161312,88161312",
+ "--runtime-init",
+ "--nice-name=system_server",
+ "com.android.server.SystemServer"
+};
+
+using namespace android;
+
+extern "C" status_t system_init();
+
+enum {
+ SYSTEM_PROCESS_TAG = DEFAULT_PROCESS_TAG+1
+};
+
+extern Mutex gEventQMutex;
+extern Condition gEventQCondition;
+
+namespace android {
+
+extern status_t app_init(const char* className);
+extern void set_finish_init_func(void (*func)());
+
+
+/**
+ * This class is used to kill this process (runtime) when the system_server dies.
+ */
+class GrimReaper : public IBinder::DeathRecipient {
+public:
+ GrimReaper() { }
+
+ virtual void binderDied(const wp<IBinder>& who)
+ {
+ LOGI("Grim Reaper killing runtime...");
+ kill(getpid(), SIGKILL);
+ }
+};
+
+extern void QuickTests();
+
+/*
+ * Print usage info.
+ */
+static void usage(const char* argv0)
+{
+ fprintf(stderr,
+ "Usage: runtime [-g gamma] [-l logfile] [-n] [-s]\n"
+ " [-j app-component] [-v app-verb] [-d app-data]\n"
+ "\n"
+ "-l: File to send log messages to\n"
+ "-n: Don't print to stdout/stderr\n"
+ "-s: Force single-process mode\n"
+ "-j: Custom home app component name\n"
+ "-v: Custom home app intent verb\n"
+ "-d: Custom home app intent data\n"
+ );
+ exit(1);
+}
+
+// Selected application to run.
+static const char* gInitialApplication = NULL;
+static const char* gInitialVerb = NULL;
+static const char* gInitialData = NULL;
+
+static void writeStringToParcel(Parcel& parcel, const char* str)
+{
+ if (str) {
+ parcel.writeString16(String16(str));
+ } else {
+ parcel.writeString16(NULL, 0);
+ }
+}
+
+/*
+ * Starting point for program logic.
+ *
+ * Returns with an exit status code (0 on success, nonzero on error).
+ */
+static int run(sp<ProcessState>& proc)
+{
+ // Temporary hack to call startRunning() on the activity manager.
+ sp<IServiceManager> sm = defaultServiceManager();
+ sp<IBinder> am;
+ while ((am = sm->getService(String16("activity"))) == NULL) {
+ LOGI("Waiting for activity manager...");
+ }
+ Parcel data, reply;
+ // XXX Need to also supply a package name for this to work again.
+ // IActivityManager::getInterfaceDescriptor() is the token for invoking on this interface;
+ // hardcoding it here avoids having to link with the full Activity Manager library
+ data.writeInterfaceToken(String16("android.app.IActivityManager"));
+ writeStringToParcel(data, NULL);
+ writeStringToParcel(data, gInitialApplication);
+ writeStringToParcel(data, gInitialVerb);
+ writeStringToParcel(data, gInitialData);
+LOGI("run() sending FIRST_CALL_TRANSACTION to activity manager");
+ am->transact(IBinder::FIRST_CALL_TRANSACTION, data, &reply);
+
+ if (proc->supportsProcesses()) {
+ // Now we link to the Activity Manager waiting for it to die. If it does kill ourself.
+ // initd will restart this process and bring the system back up.
+ sp<GrimReaper> grim = new GrimReaper();
+ am->linkToDeath(grim, grim.get(), 0);
+
+ // Now join the thread pool. Note this is needed so that the message enqueued in the driver
+ // for the linkToDeath gets processed.
+ IPCThreadState::self()->joinThreadPool();
+ } else {
+ // Keep this thread running forever...
+ while (1) {
+ usleep(100000);
+ }
+ }
+ return 1;
+}
+
+
+}; // namespace android
+
+
+/*
+ * Post-system-process initialization.
+ *
+ * This function continues initialization after the system process
+ * has been initialized. It needs to be separate because the system
+ * initialization needs to care of starting the Android runtime if it is not
+ * running in its own process, which doesn't return until the runtime is
+ * being shut down. So it will call back to here from inside of Dalvik,
+ * to allow us to continue booting up.
+ */
+static void finish_system_init(sp<ProcessState>& proc)
+{
+ // If we are running multiprocess, we now need to have the
+ // thread pool started here. We don't do this in boot_init()
+ // because when running single process we need to start the
+ // thread pool after the Android runtime has been started (so
+ // the pool uses Dalvik threads).
+ if (proc->supportsProcesses()) {
+ proc->startThreadPool();
+ }
+}
+
+
+// This function can be used to enforce security to different
+// root contexts. For now, we just give every access.
+static bool contextChecker(
+ const String16& name, const sp<IBinder>& caller, void* userData)
+{
+ return true;
+}
+
+/*
+ * Initialization of boot services.
+ *
+ * This is where we perform initialization of all of our low-level
+ * boot services. Most importantly, here we become the context
+ * manager and use that to publish the service manager that will provide
+ * access to all other services.
+ */
+static void boot_init()
+{
+ LOGI("Entered boot_init()!\n");
+
+ sp<ProcessState> proc(ProcessState::self());
+ LOGD("ProcessState: %p\n", proc.get());
+ proc->becomeContextManager(contextChecker, NULL);
+
+ if (proc->supportsProcesses()) {
+ LOGI("Binder driver opened. Multiprocess enabled.\n");
+ } else {
+ LOGI("Binder driver not found. Processes not supported.\n");
+ }
+
+ sp<BServiceManager> sm = new BServiceManager;
+ proc->setContextObject(sm);
+}
+
+/*
+ * Redirect stdin/stdout/stderr to /dev/null.
+ */
+static void redirectStdFds(void)
+{
+ int fd = open("/dev/null", O_RDWR, 0);
+ if (fd < 0) {
+ LOGW("Unable to open /dev/null: %s\n", strerror(errno));
+ } else {
+ dup2(fd, 0);
+ dup2(fd, 1);
+ dup2(fd, 2);
+ close(fd);
+ }
+}
+
+static int hasDir(const char* dir)
+{
+ struct stat s;
+ int res = stat(dir, &s);
+ if (res == 0) {
+ return S_ISDIR(s.st_mode);
+ }
+ return 0;
+}
+
+static void validateTime()
+{
+#if HAVE_ANDROID_OS
+ int fd;
+ int res;
+ time_t min_time = 1167652800; // jan 1 2007, type 'date -ud "1/1 12:00" +%s' to get value for current year
+ struct timespec ts;
+
+ fd = open("/dev/alarm", O_RDWR);
+ if(fd < 0) {
+ LOGW("Unable to open alarm driver: %s\n", strerror(errno));
+ return;
+ }
+ res = ioctl(fd, ANDROID_ALARM_GET_TIME(ANDROID_ALARM_RTC_WAKEUP), &ts);
+ if(res < 0) {
+ LOGW("Unable to read rtc, %s\n", strerror(errno));
+ }
+ else if(ts.tv_sec >= min_time) {
+ goto done;
+ }
+ LOGW("Invalid time detected, %ld set to %ld\n", ts.tv_sec, min_time);
+ ts.tv_sec = min_time;
+ ts.tv_nsec = 0;
+ res = ioctl(fd, ANDROID_ALARM_SET_RTC, &ts);
+ if(res < 0) {
+ LOGW("Unable to set rtc to %ld: %s\n", ts.tv_sec, strerror(errno));
+ }
+done:
+ close(fd);
+#endif
+}
+
+#ifndef HAVE_ANDROID_OS
+class QuickRuntime : public AndroidRuntime
+{
+public:
+ QuickRuntime() {}
+
+ virtual void onStarted()
+ {
+ printf("QuickRuntime: onStarted\n");
+ }
+};
+#endif
+
+static status_t start_process(const char* name);
+
+static void restart_me(pid_t child, void* userData)
+{
+ start_process((const char*)userData);
+}
+
+static status_t start_process(const char* name)
+{
+ String8 path(name);
+ Vector<const char*> args;
+ String8 leaf(path.getPathLeaf());
+ String8 parentDir(path.getPathDir());
+ args.insertAt(leaf.string(), 0);
+ args.add(parentDir.string());
+ args.add(NULL);
+ pid_t child = fork();
+ if (child < 0) {
+ status_t err = errno;
+ LOGE("*** fork of child %s failed: %s", leaf.string(), strerror(err));
+ return -errno;
+ } else if (child == 0) {
+ LOGI("Executing: %s", path.string());
+ execv(path.string(), const_cast<char**>(args.array()));
+ int err = errno;
+ LOGE("Exec failed: %s\n", strerror(err));
+ _exit(err);
+ } else {
+ SignalHandler::setChildHandler(child, DEFAULT_PROCESS_TAG,
+ restart_me, (void*)name);
+ }
+ return -errno;
+}
+
+/*
+ * Application entry point.
+ *
+ * Parse arguments, set some values, and pass control off to Run().
+ *
+ * This is redefined to "SDL_main" on SDL simulator builds, and
+ * "runtime_main" on wxWidgets builds.
+ */
+extern "C"
+int main(int argc, char* const argv[])
+{
+ bool singleProcess = false;
+ const char* logFile = NULL;
+ int ic;
+ int result = 1;
+ pid_t systemPid;
+
+ sp<ProcessState> proc;
+
+#ifndef HAVE_ANDROID_OS
+ /* Set stdout/stderr to unbuffered for MinGW/MSYS. */
+ //setvbuf(stdout, NULL, _IONBF, 0);
+ //setvbuf(stderr, NULL, _IONBF, 0);
+
+ LOGI("commandline args:\n");
+ for (int i = 0; i < argc; i++)
+ LOGI(" %2d: '%s'\n", i, argv[i]);
+#endif
+
+ while (1) {
+ ic = getopt(argc, argv, "g:j:v:d:l:ns");
+ if (ic < 0)
+ break;
+
+ switch (ic) {
+ case 'g':
+ break;
+ case 'j':
+ gInitialApplication = optarg;
+ break;
+ case 'v':
+ gInitialVerb = optarg;
+ break;
+ case 'd':
+ gInitialData = optarg;
+ break;
+ case 'l':
+ logFile = optarg;
+ break;
+ case 'n':
+ redirectStdFds();
+ break;
+ case 's':
+ singleProcess = true;
+ break;
+ case '?':
+ default:
+ LOGE("runtime: unrecognized flag -%c\n", ic);
+ usage(argv[0]);
+ break;
+ }
+ }
+ if (optind < argc) {
+ LOGE("runtime: extra stuff: %s\n", argv[optind]);
+ usage(argv[0]);
+ }
+
+ if (singleProcess) {
+ ProcessState::setSingleProcess(true);
+ }
+
+ if (logFile != NULL) {
+ android_logToFile(NULL, logFile);
+ }
+
+ /*
+ * Set up ANDROID_* environment variables.
+ *
+ * TODO: the use of $ANDROID_PRODUCT_OUT will go away soon.
+ */
+ static const char* kSystemDir = "/system";
+ static const char* kDataDir = "/data";
+ static const char* kAppSubdir = "/app";
+ const char* out = NULL;
+#ifndef HAVE_ANDROID_OS
+ //out = getenv("ANDROID_PRODUCT_OUT");
+#endif
+ if (out == NULL)
+ out = "";
+
+ char* systemDir = (char*) malloc(strlen(out) + strlen(kSystemDir) +1);
+ char* dataDir = (char*) malloc(strlen(out) + strlen(kDataDir) +1);
+
+ sprintf(systemDir, "%s%s", out, kSystemDir);
+ sprintf(dataDir, "%s%s", out, kDataDir);
+ setenv("ANDROID_ROOT", systemDir, 1);
+ setenv("ANDROID_DATA", dataDir, 1);
+
+ char* assetDir = (char*) malloc(strlen(systemDir) + strlen(kAppSubdir) +1);
+ sprintf(assetDir, "%s%s", systemDir, kAppSubdir);
+
+ LOGI("Startup: sys='%s' asset='%s' data='%s'\n",
+ systemDir, assetDir, dataDir);
+ free(systemDir);
+ free(dataDir);
+
+#ifdef HAVE_ANDROID_OS
+ /* set up a process group for easier killing on the device */
+ setpgid(0, getpid());
+#endif
+
+ // Change to asset dir. This is only necessary if we've changed to
+ // a different directory, but there's little harm in doing it regardless.
+ //
+ // Expecting assets to live in the current dir is not a great idea,
+ // because some of our code or one of our libraries could change the
+ // directory out from under us. Preserve the behavior for now.
+ if (chdir(assetDir) != 0) {
+ LOGW("WARNING: could not change dir to '%s': %s\n",
+ assetDir, strerror(errno));
+ }
+ free(assetDir);
+
+#if 0
+ // Hack to keep libc from beating the filesystem to death. It's
+ // hitting /etc/localtime frequently,
+ //
+ // This statement locks us into Pacific time. We could do better,
+ // but there's not much point until we're sure that the library
+ // can't be changed to do more along the lines of what we want.
+#ifndef XP_WIN
+ setenv("TZ", "PST+8PDT,M4.1.0/2,M10.5.0/2", true);
+#endif
+#endif
+
+ /* track our progress through the boot sequence */
+ const int LOG_BOOT_PROGRESS_START = 3000;
+ LOG_EVENT_LONG(LOG_BOOT_PROGRESS_START,
+ ns2ms(systemTime(SYSTEM_TIME_MONOTONIC)));
+
+ validateTime();
+
+ proc = ProcessState::self();
+
+ boot_init();
+
+ /* If we are in multiprocess mode, have zygote spawn the system
+ * server process and call system_init(). If we are running in
+ * single process mode just call system_init() directly.
+ */
+ if (proc->supportsProcesses()) {
+ // If stdio logging is on, system_server should not inherit our stdio
+ // The dalvikvm instance will copy stdio to the log on its own
+ char propBuf[PROPERTY_VALUE_MAX];
+ bool logStdio = false;
+ property_get("log.redirect-stdio", propBuf, "");
+ logStdio = (strcmp(propBuf, "true") == 0);
+
+ zygote_run_oneshot((int)(!logStdio),
+ sizeof(ZYGOTE_ARGV) / sizeof(ZYGOTE_ARGV[0]),
+ ZYGOTE_ARGV);
+
+ //start_process("/system/bin/mediaserver");
+
+ } else {
+#ifndef HAVE_ANDROID_OS
+ QuickRuntime* runt = new QuickRuntime();
+ runt->start("com/android/server/SystemServer",
+ false /* spontaneously fork system server from zygote */);
+#endif
+ }
+
+ //printf("+++ post-zygote\n");
+
+ finish_system_init(proc);
+ run(proc);
+
+bail:
+ if (proc != NULL) {
+ proc->setContextObject(NULL);
+ }
+
+ return 0;
+}