diff options
author | The Android Open Source Project <initial-contribution@android.com> | 2009-03-03 19:31:44 -0800 |
---|---|---|
committer | The Android Open Source Project <initial-contribution@android.com> | 2009-03-03 19:31:44 -0800 |
commit | edbf3b6af777b721cd2a1ef461947e51e88241e1 (patch) | |
tree | f09427b843b192cccf8c3b5328cb81dddf6489fa /cmds/runtime | |
parent | d5193d9394c5e58176d7bcdf50ef017f8a3b9e1e (diff) | |
download | frameworks_native-edbf3b6af777b721cd2a1ef461947e51e88241e1.zip frameworks_native-edbf3b6af777b721cd2a1ef461947e51e88241e1.tar.gz frameworks_native-edbf3b6af777b721cd2a1ef461947e51e88241e1.tar.bz2 |
auto import from //depot/cupcake/@135843
Diffstat (limited to 'cmds/runtime')
-rw-r--r-- | cmds/runtime/Android.mk | 29 | ||||
-rw-r--r-- | cmds/runtime/MODULE_LICENSE_APACHE2 | 0 | ||||
-rw-r--r-- | cmds/runtime/NOTICE | 190 | ||||
-rw-r--r-- | cmds/runtime/ServiceManager.cpp | 74 | ||||
-rw-r--r-- | cmds/runtime/ServiceManager.h | 38 | ||||
-rw-r--r-- | cmds/runtime/SignalHandler.cpp | 249 | ||||
-rw-r--r-- | cmds/runtime/SignalHandler.h | 137 | ||||
-rw-r--r-- | cmds/runtime/main_runtime.cpp | 514 |
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; +} |