Home | History | Annotate | Download | only in app_process
      1 /*
      2  * Main entry of app process.
      3  *
      4  * Starts the interpreted runtime, then starts up the application.
      5  *
      6  */
      7 
      8 #define LOG_TAG "appproc"
      9 
     10 #include <stdio.h>
     11 #include <stdlib.h>
     12 #include <sys/prctl.h>
     13 #include <sys/stat.h>
     14 #include <unistd.h>
     15 
     16 #include <binder/IPCThreadState.h>
     17 #include <hwbinder/IPCThreadState.h>
     18 #include <utils/Log.h>
     19 #include <cutils/memory.h>
     20 #include <cutils/properties.h>
     21 #include <cutils/trace.h>
     22 #include <android_runtime/AndroidRuntime.h>
     23 #include <private/android_filesystem_config.h>  // for AID_SYSTEM
     24 
     25 namespace android {
     26 
     27 static void app_usage()
     28 {
     29     fprintf(stderr,
     30         "Usage: app_process [java-options] cmd-dir start-class-name [options]\n");
     31 }
     32 
     33 class AppRuntime : public AndroidRuntime
     34 {
     35 public:
     36     AppRuntime(char* argBlockStart, const size_t argBlockLength)
     37         : AndroidRuntime(argBlockStart, argBlockLength)
     38         , mClass(NULL)
     39     {
     40     }
     41 
     42     void setClassNameAndArgs(const String8& className, int argc, char * const *argv) {
     43         mClassName = className;
     44         for (int i = 0; i < argc; ++i) {
     45              mArgs.add(String8(argv[i]));
     46         }
     47     }
     48 
     49     virtual void onVmCreated(JNIEnv* env)
     50     {
     51         if (mClassName.isEmpty()) {
     52             return; // Zygote. Nothing to do here.
     53         }
     54 
     55         /*
     56          * This is a little awkward because the JNI FindClass call uses the
     57          * class loader associated with the native method we're executing in.
     58          * If called in onStarted (from RuntimeInit.finishInit because we're
     59          * launching "am", for example), FindClass would see that we're calling
     60          * from a boot class' native method, and so wouldn't look for the class
     61          * we're trying to look up in CLASSPATH. Unfortunately it needs to,
     62          * because the "am" classes are not boot classes.
     63          *
     64          * The easiest fix is to call FindClass here, early on before we start
     65          * executing boot class Java code and thereby deny ourselves access to
     66          * non-boot classes.
     67          */
     68         char* slashClassName = toSlashClassName(mClassName.string());
     69         mClass = env->FindClass(slashClassName);
     70         if (mClass == NULL) {
     71             ALOGE("ERROR: could not find class '%s'\n", mClassName.string());
     72         }
     73         free(slashClassName);
     74 
     75         mClass = reinterpret_cast<jclass>(env->NewGlobalRef(mClass));
     76     }
     77 
     78     virtual void onStarted()
     79     {
     80         sp<ProcessState> proc = ProcessState::self();
     81         ALOGV("App process: starting thread pool.\n");
     82         proc->startThreadPool();
     83 
     84         AndroidRuntime* ar = AndroidRuntime::getRuntime();
     85         ar->callMain(mClassName, mClass, mArgs);
     86 
     87         IPCThreadState::self()->stopProcess();
     88         hardware::IPCThreadState::self()->stopProcess();
     89     }
     90 
     91     virtual void onZygoteInit()
     92     {
     93         sp<ProcessState> proc = ProcessState::self();
     94         ALOGV("App process: starting thread pool.\n");
     95         proc->startThreadPool();
     96     }
     97 
     98     virtual void onExit(int code)
     99     {
    100         if (mClassName.isEmpty()) {
    101             // if zygote
    102             IPCThreadState::self()->stopProcess();
    103             hardware::IPCThreadState::self()->stopProcess();
    104         }
    105 
    106         AndroidRuntime::onExit(code);
    107     }
    108 
    109 
    110     String8 mClassName;
    111     Vector<String8> mArgs;
    112     jclass mClass;
    113 };
    114 
    115 }
    116 
    117 using namespace android;
    118 
    119 static size_t computeArgBlockSize(int argc, char* const argv[]) {
    120     // TODO: This assumes that all arguments are allocated in
    121     // contiguous memory. There isn't any documented guarantee
    122     // that this is the case, but this is how the kernel does it
    123     // (see fs/exec.c).
    124     //
    125     // Also note that this is a constant for "normal" android apps.
    126     // Since they're forked from zygote, the size of their command line
    127     // is the size of the zygote command line.
    128     //
    129     // We change the process name of the process by over-writing
    130     // the start of the argument block (argv[0]) with the new name of
    131     // the process, so we'd mysteriously start getting truncated process
    132     // names if the zygote command line decreases in size.
    133     uintptr_t start = reinterpret_cast<uintptr_t>(argv[0]);
    134     uintptr_t end = reinterpret_cast<uintptr_t>(argv[argc - 1]);
    135     end += strlen(argv[argc - 1]) + 1;
    136     return (end - start);
    137 }
    138 
    139 static void maybeCreateDalvikCache() {
    140 #if defined(__aarch64__)
    141     static const char kInstructionSet[] = "arm64";
    142 #elif defined(__x86_64__)
    143     static const char kInstructionSet[] = "x86_64";
    144 #elif defined(__arm__)
    145     static const char kInstructionSet[] = "arm";
    146 #elif defined(__i386__)
    147     static const char kInstructionSet[] = "x86";
    148 #elif defined (__mips__) && !defined(__LP64__)
    149     static const char kInstructionSet[] = "mips";
    150 #elif defined (__mips__) && defined(__LP64__)
    151     static const char kInstructionSet[] = "mips64";
    152 #else
    153 #error "Unknown instruction set"
    154 #endif
    155     const char* androidRoot = getenv("ANDROID_DATA");
    156     LOG_ALWAYS_FATAL_IF(androidRoot == NULL, "ANDROID_DATA environment variable unset");
    157 
    158     char dalvikCacheDir[PATH_MAX];
    159     const int numChars = snprintf(dalvikCacheDir, PATH_MAX,
    160             "%s/dalvik-cache/%s", androidRoot, kInstructionSet);
    161     LOG_ALWAYS_FATAL_IF((numChars >= PATH_MAX || numChars < 0),
    162             "Error constructing dalvik cache : %s", strerror(errno));
    163 
    164     int result = mkdir(dalvikCacheDir, 0711);
    165     LOG_ALWAYS_FATAL_IF((result < 0 && errno != EEXIST),
    166             "Error creating cache dir %s : %s", dalvikCacheDir, strerror(errno));
    167 
    168     // We always perform these steps because the directory might
    169     // already exist, with wider permissions and a different owner
    170     // than we'd like.
    171     result = chown(dalvikCacheDir, AID_ROOT, AID_ROOT);
    172     LOG_ALWAYS_FATAL_IF((result < 0), "Error changing dalvik-cache ownership : %s", strerror(errno));
    173 
    174     result = chmod(dalvikCacheDir, 0711);
    175     LOG_ALWAYS_FATAL_IF((result < 0),
    176             "Error changing dalvik-cache permissions : %s", strerror(errno));
    177 }
    178 
    179 #if defined(__LP64__)
    180 static const char ABI_LIST_PROPERTY[] = "ro.product.cpu.abilist64";
    181 static const char ZYGOTE_NICE_NAME[] = "zygote64";
    182 #else
    183 static const char ABI_LIST_PROPERTY[] = "ro.product.cpu.abilist32";
    184 static const char ZYGOTE_NICE_NAME[] = "zygote";
    185 #endif
    186 
    187 int main(int argc, char* const argv[])
    188 {
    189     if (!LOG_NDEBUG) {
    190       String8 argv_String;
    191       for (int i = 0; i < argc; ++i) {
    192         argv_String.append("\"");
    193         argv_String.append(argv[i]);
    194         argv_String.append("\" ");
    195       }
    196       ALOGV("app_process main with argv: %s", argv_String.string());
    197     }
    198 
    199     AppRuntime runtime(argv[0], computeArgBlockSize(argc, argv));
    200     // Process command line arguments
    201     // ignore argv[0]
    202     argc--;
    203     argv++;
    204 
    205     // Everything up to '--' or first non '-' arg goes to the vm.
    206     //
    207     // The first argument after the VM args is the "parent dir", which
    208     // is currently unused.
    209     //
    210     // After the parent dir, we expect one or more the following internal
    211     // arguments :
    212     //
    213     // --zygote : Start in zygote mode
    214     // --start-system-server : Start the system server.
    215     // --application : Start in application (stand alone, non zygote) mode.
    216     // --nice-name : The nice name for this process.
    217     //
    218     // For non zygote starts, these arguments will be followed by
    219     // the main class name. All remaining arguments are passed to
    220     // the main method of this class.
    221     //
    222     // For zygote starts, all remaining arguments are passed to the zygote.
    223     // main function.
    224     //
    225     // Note that we must copy argument string values since we will rewrite the
    226     // entire argument block when we apply the nice name to argv0.
    227     //
    228     // As an exception to the above rule, anything in "spaced commands"
    229     // goes to the vm even though it has a space in it.
    230     const char* spaced_commands[] = { "-cp", "-classpath" };
    231     // Allow "spaced commands" to be succeeded by exactly 1 argument (regardless of -s).
    232     bool known_command = false;
    233 
    234     int i;
    235     for (i = 0; i < argc; i++) {
    236         if (known_command == true) {
    237           runtime.addOption(strdup(argv[i]));
    238           ALOGV("app_process main add known option '%s'", argv[i]);
    239           known_command = false;
    240           continue;
    241         }
    242 
    243         for (int j = 0;
    244              j < static_cast<int>(sizeof(spaced_commands) / sizeof(spaced_commands[0]));
    245              ++j) {
    246           if (strcmp(argv[i], spaced_commands[j]) == 0) {
    247             known_command = true;
    248             ALOGV("app_process main found known command '%s'", argv[i]);
    249           }
    250         }
    251 
    252         if (argv[i][0] != '-') {
    253             break;
    254         }
    255         if (argv[i][1] == '-' && argv[i][2] == 0) {
    256             ++i; // Skip --.
    257             break;
    258         }
    259 
    260         runtime.addOption(strdup(argv[i]));
    261         ALOGV("app_process main add option '%s'", argv[i]);
    262     }
    263 
    264     // Parse runtime arguments.  Stop at first unrecognized option.
    265     bool zygote = false;
    266     bool startSystemServer = false;
    267     bool application = false;
    268     String8 niceName;
    269     String8 className;
    270 
    271     ++i;  // Skip unused "parent dir" argument.
    272     while (i < argc) {
    273         const char* arg = argv[i++];
    274         if (strcmp(arg, "--zygote") == 0) {
    275             zygote = true;
    276             niceName = ZYGOTE_NICE_NAME;
    277         } else if (strcmp(arg, "--start-system-server") == 0) {
    278             startSystemServer = true;
    279         } else if (strcmp(arg, "--application") == 0) {
    280             application = true;
    281         } else if (strncmp(arg, "--nice-name=", 12) == 0) {
    282             niceName.setTo(arg + 12);
    283         } else if (strncmp(arg, "--", 2) != 0) {
    284             className.setTo(arg);
    285             break;
    286         } else {
    287             --i;
    288             break;
    289         }
    290     }
    291 
    292     Vector<String8> args;
    293     if (!className.isEmpty()) {
    294         // We're not in zygote mode, the only argument we need to pass
    295         // to RuntimeInit is the application argument.
    296         //
    297         // The Remainder of args get passed to startup class main(). Make
    298         // copies of them before we overwrite them with the process name.
    299         args.add(application ? String8("application") : String8("tool"));
    300         runtime.setClassNameAndArgs(className, argc - i, argv + i);
    301 
    302         if (!LOG_NDEBUG) {
    303           String8 restOfArgs;
    304           char* const* argv_new = argv + i;
    305           int argc_new = argc - i;
    306           for (int k = 0; k < argc_new; ++k) {
    307             restOfArgs.append("\"");
    308             restOfArgs.append(argv_new[k]);
    309             restOfArgs.append("\" ");
    310           }
    311           ALOGV("Class name = %s, args = %s", className.string(), restOfArgs.string());
    312         }
    313     } else {
    314         // We're in zygote mode.
    315         maybeCreateDalvikCache();
    316 
    317         if (startSystemServer) {
    318             args.add(String8("start-system-server"));
    319         }
    320 
    321         char prop[PROP_VALUE_MAX];
    322         if (property_get(ABI_LIST_PROPERTY, prop, NULL) == 0) {
    323             LOG_ALWAYS_FATAL("app_process: Unable to determine ABI list from property %s.",
    324                 ABI_LIST_PROPERTY);
    325             return 11;
    326         }
    327 
    328         String8 abiFlag("--abi-list=");
    329         abiFlag.append(prop);
    330         args.add(abiFlag);
    331 
    332         // In zygote mode, pass all remaining arguments to the zygote
    333         // main() method.
    334         for (; i < argc; ++i) {
    335             args.add(String8(argv[i]));
    336         }
    337     }
    338 
    339     if (!niceName.isEmpty()) {
    340         runtime.setArgv0(niceName.string(), true /* setProcName */);
    341     }
    342 
    343     if (zygote) {
    344         runtime.start("com.android.internal.os.ZygoteInit", args, zygote);
    345     } else if (className) {
    346         runtime.start("com.android.internal.os.RuntimeInit", args, zygote);
    347     } else {
    348         fprintf(stderr, "Error: no class name or --zygote supplied.\n");
    349         app_usage();
    350         LOG_ALWAYS_FATAL("app_process: no class name or --zygote supplied.");
    351     }
    352 }
    353