1/*
2 * Copyright (C) 2011 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package com.android.internal.os;
18
19import android.os.Process;
20import android.util.Slog;
21
22import java.io.DataOutputStream;
23import java.io.FileDescriptor;
24import java.io.FileOutputStream;
25import java.io.IOException;
26
27import libcore.io.IoUtils;
28import libcore.io.Libcore;
29
30import dalvik.system.Zygote;
31
32/**
33 * Startup class for the wrapper process.
34 * @hide
35 */
36public class WrapperInit {
37    private final static String TAG = "AndroidRuntime";
38
39    /**
40     * Class not instantiable.
41     */
42    private WrapperInit() {
43    }
44
45    /**
46     * The main function called when starting a runtime application through a
47     * wrapper process instead of by forking Zygote.
48     *
49     * The first argument specifies the file descriptor for a pipe that should receive
50     * the pid of this process, or 0 if none.
51     *
52     * The second argument is the target SDK version for the app.
53     *
54     * The remaining arguments are passed to the runtime.
55     *
56     * @param args The command-line arguments.
57     */
58    public static void main(String[] args) {
59        try {
60            // Parse our mandatory arguments.
61            int fdNum = Integer.parseInt(args[0], 10);
62            int targetSdkVersion = Integer.parseInt(args[1], 10);
63
64            // Tell the Zygote what our actual PID is (since it only knows about the
65            // wrapper that it directly forked).
66            if (fdNum != 0) {
67                try {
68                    FileDescriptor fd = ZygoteInit.createFileDescriptor(fdNum);
69                    DataOutputStream os = new DataOutputStream(new FileOutputStream(fd));
70                    os.writeInt(Process.myPid());
71                    os.close();
72                    IoUtils.closeQuietly(fd);
73                } catch (IOException ex) {
74                    Slog.d(TAG, "Could not write pid of wrapped process to Zygote pipe.", ex);
75                }
76            }
77
78            // Mimic Zygote preloading.
79            ZygoteInit.preload();
80
81            // Launch the application.
82            String[] runtimeArgs = new String[args.length - 2];
83            System.arraycopy(args, 2, runtimeArgs, 0, runtimeArgs.length);
84            RuntimeInit.wrapperInit(targetSdkVersion, runtimeArgs);
85        } catch (ZygoteInit.MethodAndArgsCaller caller) {
86            caller.run();
87        }
88    }
89
90    /**
91     * Executes a runtime application with a wrapper command.
92     * This method never returns.
93     *
94     * @param invokeWith The wrapper command.
95     * @param niceName The nice name for the application, or null if none.
96     * @param targetSdkVersion The target SDK version for the app.
97     * @param pipeFd The pipe to which the application's pid should be written, or null if none.
98     * @param args Arguments for {@link RuntimeInit.main}.
99     */
100    public static void execApplication(String invokeWith, String niceName,
101            int targetSdkVersion, FileDescriptor pipeFd, String[] args) {
102        StringBuilder command = new StringBuilder(invokeWith);
103        command.append(" /system/bin/app_process /system/bin --application");
104        if (niceName != null) {
105            command.append(" '--nice-name=").append(niceName).append("'");
106        }
107        command.append(" com.android.internal.os.WrapperInit ");
108        command.append(pipeFd != null ? pipeFd.getInt$() : 0);
109        command.append(' ');
110        command.append(targetSdkVersion);
111        Zygote.appendQuotedShellArgs(command, args);
112        Zygote.execShell(command.toString());
113    }
114
115    /**
116     * Executes a standalone application with a wrapper command.
117     * This method never returns.
118     *
119     * @param invokeWith The wrapper command.
120     * @param classPath The class path.
121     * @param className The class name to invoke.
122     * @param args Arguments for the main() method of the specified class.
123     */
124    public static void execStandalone(String invokeWith, String classPath, String className,
125            String[] args) {
126        StringBuilder command = new StringBuilder(invokeWith);
127        command.append(" /system/bin/dalvikvm -classpath '").append(classPath);
128        command.append("' ").append(className);
129        Zygote.appendQuotedShellArgs(command, args);
130        Zygote.execShell(command.toString());
131    }
132}
133