• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2018 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 
17 package android.os;
18 
19 import static android.os.Process.ZYGOTE_POLICY_FLAG_EMPTY;
20 
21 import android.annotation.NonNull;
22 import android.annotation.Nullable;
23 import android.content.pm.ApplicationInfo;
24 import android.content.pm.ProcessInfo;
25 import android.util.Log;
26 import android.util.Pair;
27 
28 import com.android.internal.annotations.GuardedBy;
29 import com.android.internal.os.Zygote;
30 
31 import dalvik.system.VMRuntime;
32 
33 import java.util.Map;
34 
35 /**
36  * AppZygote is responsible for interfacing with an application-specific zygote.
37  *
38  * Application zygotes can pre-load app-specific code and data, and this interface can
39  * be used to spawn isolated services from such an application zygote.
40  *
41  * Note that we'll have only one instance of this per application / uid combination.
42  *
43  * @hide
44  */
45 public class AppZygote {
46     private static final String LOG_TAG = "AppZygote";
47 
48     // UID of the Zygote itself
49     private final int mZygoteUid;
50 
51     // First UID/GID of the range the AppZygote can setuid()/setgid() to
52     private final int mZygoteUidGidMin;
53 
54     // Last UID/GID of the range the AppZygote can setuid()/setgid() to
55     private final int mZygoteUidGidMax;
56 
57     private final Object mLock = new Object();
58 
59     /**
60      * Instance that maintains the socket connection to the zygote. This is {@code null} if the
61      * zygote is not running or is not connected.
62      */
63     @GuardedBy("mLock")
64     private ChildZygoteProcess mZygote;
65 
66     private final ApplicationInfo mAppInfo;
67     private final ProcessInfo mProcessInfo;
68 
AppZygote(ApplicationInfo appInfo, ProcessInfo processInfo, int zygoteUid, int uidGidMin, int uidGidMax)69     public AppZygote(ApplicationInfo appInfo, ProcessInfo processInfo, int zygoteUid, int uidGidMin,
70             int uidGidMax) {
71         mAppInfo = appInfo;
72         mProcessInfo = processInfo;
73         mZygoteUid = zygoteUid;
74         mZygoteUidGidMin = uidGidMin;
75         mZygoteUidGidMax = uidGidMax;
76     }
77 
78     /**
79      * Returns the zygote process associated with this app zygote.
80      * Creates the process if it's not already running.
81      */
getProcess()82     public ChildZygoteProcess getProcess() {
83         synchronized (mLock) {
84             if (mZygote != null) return mZygote;
85 
86             connectToZygoteIfNeededLocked();
87             return mZygote;
88         }
89     }
90 
91     /**
92      * Stops the Zygote and kills the zygote process.
93      */
stopZygote()94     public void stopZygote() {
95         synchronized (mLock) {
96             stopZygoteLocked();
97         }
98     }
99 
getAppInfo()100     public ApplicationInfo getAppInfo() {
101         return mAppInfo;
102     }
103 
104     /**
105      * Start a new process.
106      *
107      * <p>Wrap ZygoteProcess.start with retry logic.
108      *
109      * @param processClass The class to use as the process's main entry
110      *                     point.
111      * @param niceName A more readable name to use for the process.
112      * @param uid The user-id under which the process will run.
113      * @param gids Additional group-ids associated with the process.
114      * @param runtimeFlags Additional flags.
115      * @param targetSdkVersion The target SDK version for the app.
116      * @param seInfo null-ok SELinux information for the new process.
117      * @param abi non-null the ABI this app should be started with.
118      * @param instructionSet null-ok the instruction set to use.
119      * @param appDataDir null-ok the data directory of the app.
120      * @param packageName null-ok the name of the package this process belongs to.
121      * @param isTopApp Whether the process starts for high priority application.
122      * @param disabledCompatChanges null-ok list of disabled compat changes for the process being
123      *                             started.
124      * @param pkgDataInfoMap Map from related package names to private data directory
125      *                       volume UUID and inode number.
126      * @param allowlistedDataInfoList Map from allowlisted package names to private data directory
127      *                       volume UUID and inode number.
128      * @param zygoteArgs Additional arguments to supply to the Zygote process.
129      * @return An object that describes the result of the attempt to start the process.
130      * @throws RuntimeException on fatal start failure
131      */
startProcess(@onNull final String processClass, final String niceName, int uid, @Nullable int[] gids, int runtimeFlags, int mountExternal, int targetSdkVersion, @Nullable String seInfo, @NonNull String abi, @Nullable String instructionSet, @Nullable String appDataDir, @Nullable String packageName, boolean isTopApp, @Nullable long[] disabledCompatChanges, @Nullable Map<String, Pair<String, Long>> pkgDataInfoMap, @Nullable Map<String, Pair<String, Long>> allowlistedDataInfoList, @Nullable String[] zygoteArgs)132     public final Process.ProcessStartResult startProcess(@NonNull final String processClass,
133             final String niceName,
134             int uid, @Nullable int[] gids,
135             int runtimeFlags, int mountExternal,
136             int targetSdkVersion,
137             @Nullable String seInfo,
138             @NonNull String abi,
139             @Nullable String instructionSet,
140             @Nullable String appDataDir,
141             @Nullable String packageName,
142             boolean isTopApp,
143             @Nullable long[] disabledCompatChanges,
144             @Nullable Map<String, Pair<String, Long>>
145             pkgDataInfoMap,
146             @Nullable Map<String, Pair<String, Long>>
147             allowlistedDataInfoList,
148             @Nullable String[] zygoteArgs) {
149         try {
150             return getProcess().start(processClass,
151                     niceName, uid, uid, gids, runtimeFlags, mountExternal,
152                     targetSdkVersion, seInfo, abi, instructionSet,
153                     appDataDir, null, packageName,
154                     /*zygotePolicyFlags=*/ ZYGOTE_POLICY_FLAG_EMPTY, isTopApp,
155                     disabledCompatChanges, pkgDataInfoMap, allowlistedDataInfoList,
156                     false, false, false,
157                     zygoteArgs);
158         } catch (RuntimeException e) {
159             if (!Flags.appZygoteRetryStart()) {
160                 throw e;
161             }
162             final boolean zygote_dead = getProcess().isDead();
163             if (!zygote_dead) {
164                 throw e; // Zygote process is alive. Do nothing.
165             }
166         }
167         // Retry here if the previous start fails.
168         Log.w(LOG_TAG, "retry starting process " + niceName);
169         stopZygote();
170         return getProcess().start(processClass,
171                 niceName, uid, uid, gids, runtimeFlags, mountExternal,
172                 targetSdkVersion, seInfo, abi, instructionSet,
173                 appDataDir, null, packageName,
174                 /*zygotePolicyFlags=*/ ZYGOTE_POLICY_FLAG_EMPTY, isTopApp,
175                 disabledCompatChanges, pkgDataInfoMap, allowlistedDataInfoList,
176                 false, false, false,
177                 zygoteArgs);
178     }
179 
180     @GuardedBy("mLock")
stopZygoteLocked()181     private void stopZygoteLocked() {
182         if (mZygote != null) {
183             mZygote.close();
184             // use killProcessGroup() here, so we kill all untracked children as well.
185             if (!mZygote.isDead()) {
186                 Process.killProcessGroup(mZygoteUid, mZygote.getPid());
187             }
188             mZygote = null;
189         }
190     }
191 
192     @GuardedBy("mLock")
connectToZygoteIfNeededLocked()193     private void connectToZygoteIfNeededLocked() {
194         String abi = mAppInfo.primaryCpuAbi != null ? mAppInfo.primaryCpuAbi :
195                 Build.SUPPORTED_ABIS[0];
196         try {
197             int runtimeFlags = Zygote.getMemorySafetyRuntimeFlagsForSecondaryZygote(
198                     mAppInfo, mProcessInfo);
199 
200             final int[] sharedAppGid = {
201                     UserHandle.getSharedAppGid(UserHandle.getAppId(mAppInfo.uid)) };
202             mZygote = Process.ZYGOTE_PROCESS.startChildZygote(
203                     "com.android.internal.os.AppZygoteInit",
204                     mAppInfo.processName + "_zygote",
205                     mZygoteUid,
206                     mZygoteUid,
207                     sharedAppGid,  // Zygote gets access to shared app GID for profiles
208                     runtimeFlags,
209                     "app_zygote",  // seInfo
210                     abi,  // abi
211                     abi, // acceptedAbiList
212                     VMRuntime.getInstructionSet(abi), // instructionSet
213                     mZygoteUidGidMin,
214                     mZygoteUidGidMax);
215 
216             ZygoteProcess.waitForConnectionToZygote(mZygote.getPrimarySocketAddress());
217             // preload application code in the zygote
218             Log.i(LOG_TAG, "Starting application preload.");
219             mZygote.preloadApp(mAppInfo, abi);
220             Log.i(LOG_TAG, "Application preload done.");
221         } catch (Exception e) {
222             Log.e(LOG_TAG, "Error connecting to app zygote", e);
223             stopZygoteLocked();
224         }
225     }
226 }
227