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