summaryrefslogtreecommitdiffstats
path: root/cmds/runtime/main_runtime.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'cmds/runtime/main_runtime.cpp')
-rw-r--r--cmds/runtime/main_runtime.cpp514
1 files changed, 514 insertions, 0 deletions
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;
+}