Android アプリケーションが起動するまでの流れ
まとめ
※クリックすると大きな図が開きます
※プロセスの親子関係に注意
$ ps USER PID PPID VSIZE RSS WCHAN PC NAME root 1 0 268 180 c009b74c 0000875c S /init root 33 1 60924 16448 c009b74c afd0b844 S zygote system 62 33 130944 27412 ffffffff afd0b6fc S system_server app_29 122 33 82996 21988 ffffffff afd0c51c S com.android.launcher app_9 476 33 78500 20568 ffffffff afd0c51c S jp.klab.stone :
コード読み
以下はソースコードを追った記録です。
なお、例の一件以来 android.git.kernel.org のダウン状態が続いているため、記事中のコードは android.git.linaro.org 上の最新版(2011年 9月末現在)からの引用です。
■ Zygote プロセスの起動(システムブート時) - /init.rc - frameworks/base/cmds/app_process/app_main.cpp ・main() - frameworks/base/core/java/com/android/internal/os/ZygoteInit.java ・main() ■ 1. Launcher のアプリをタップ〜Activity Manager へ要求を投げるまで - packages/apps/Launcher2/src/com/android/launcher2/Launcher.java ・onClick() ・startActivitySafely() - frameworks/base/core/java/android/app/Activity.java ・startActivity() ・startActivityForResult() - frameworks/base/core/java/android/app/Instrumentation.java ・execStartActivity() - frameworks/base/core/java/android/app/ActivityManagerNative.java ・getDefault() ■ 2. Activity Manager が Zygote へプロセス生成要求を投げるまで - frameworks/base/services/java/com/android/server/am/ActivityManagerService.java ・startActivity() - frameworks/base/services/java/com/android/server/am/ActivityStack.java ・startActivityMayWait() ・startActivityLocked() ・startActivityUncheckedLocked() ・startActivityLocked() ・resumeTopActivityLocked() ・startSpecificActivityLocked() - frameworks/base/services/java/com/android/server/am/ActivityManagerService.java ・startProcessLocked() ・startProcessLocked() - frameworks/base/core/java/android/os/Process.java ・start() ・startViaZygote() ・zygoteSendArgsAndGetResult() ■ 3. 要求を受け取った Zygote がプロセスを fork するまで - frameworks/base/core/java/com/android/internal/os/ZygoteInit.java ・runSelectLoopMode() ・acceptCommandPeer() - frameworks/base/core/java/com/android/internal/os/ZygoteConnectionjava ・ZygoteConnection() ・runOnce() ・applyUidSecurityPolicy() ■ 4. fork されたプロセスが Activity Manager へ対象アプリ情報を照会するまで - frameworks/base/core/java/com/android/internal/os/ZygoteConnection.java ・handleChildProc() - frameworks/base/core/java/com/android/internal/os/RuntimeInit.java ・zygoteInit() ・applicationInit() ・invokeStaticMain() - frameworks/base/core/java/com/android/internal/os/ZygoteInit.java ・main() - frameworks/base/core/java/android/app/ActivityThread.java ・main() ・attach() ■ 5. Activity Manager が新規プロセスに起動対象アプリ情報を渡すまで - frameworks/base/services/java/com/android/server/am/ActivityManagerService.java ・attachApplication() ・attachApplicationLocked() ■ 6. 新プロセスが Activity Manager からの情報をもとにアプリを起動するまで - frameworks/base/core/java/android/app/ActivityThread.java ・bindApplication() ・queueOrSendMessage() ・handleMessage() ・handleBindApplication() - frameworks/base/core/java/android/app/LoadedApk.java ・makeApplication() - frameworks/base/core/java/android/app/Instrumentation.java ・newApplication() ・newApplication() ・callApplicationOnCreate()
Zygote プロセスの起動(システムブート時)
/init.rc (実行環境より引用)
: service zygote /system/bin/app_process -Xzygote /system/bin --zygote --start-system-server socket zygote stream 666 onrestart write /sys/android_power/request_state wake onrestart write /sys/power/state on onrestart restart media onrestart restart netd :
frameworks/base/cmds/app_process/app_main.cpp
118 int main(int argc, const char* const argv[]) 119 { : 149 while (i < argc) { 150 const char* arg = argv[i++]; 151 if (!parentDir) { 152 parentDir = arg; 153 } else if (strcmp(arg, "--zygote") == 0) { 154 zygote = true; 155 niceName = "zygote"; 156 } else if (strcmp(arg, "--start-system-server") == 0) { 157 startSystemServer = true; 158 } else if (strcmp(arg, "--application") == 0) { 159 application = true; 160 } else if (strncmp(arg, "--nice-name=", 12) == 0) { 161 niceName = arg + 12; 162 } else { 163 className = arg; 164 break; 165 } 166 } 167 168 if (niceName && *niceName) { 169 setArgv0(argv0, niceName); 170 set_process_name(niceName); 171 } 172 173 runtime.mParentDir = parentDir; 174 175 if (zygote) { 176 runtime.start("com.android.internal.os.ZygoteInit", 177 startSystemServer ? "start-system-server" : "");
frameworks/base/core/java/com/android/internal/os/ZygoteInit.java
17 package com.android.internal.os; : 563 public static void main(String argv[]) { 564 try { 565 VMRuntime.getRuntime().setMinimumHeapSize(5 * 1024 * 1024); 566 567 // Start profiling the zygote initialization. 568 SamplingProfilerIntegration.start(); 569 570 registerZygoteSocket(); →/dev/socket/zygote を作成 571 EventLog.writeEvent(LOG_BOOT_PROGRESS_PRELOAD_START, 572 SystemClock.uptimeMillis()); 573 preload(); →preloaded-classesに記述されたクラスとリソースをプリロード 574 EventLog.writeEvent(LOG_BOOT_PROGRESS_PRELOAD_END, 575 SystemClock.uptimeMillis()); 576 577 // Finish profiling the zygote initialization. 578 SamplingProfilerIntegration.writeZygoteSnapshot(); 579 580 // Do an initial gc to clean up after startup 581 gc(); 582 583 // If requested, start system server directly from Zygote 584 if (argv.length != 2) { 585 throw new RuntimeException(argv[0] + USAGE_STRING); 586 } 587 588 if (argv[1].equals("start-system-server")) { 589 startSystemServer(); →system_server プロセスを起動 590 } else if (!argv[1].equals("")) { 591 throw new RuntimeException(argv[0] + USAGE_STRING); 592 } 593 594 Log.i(TAG, "Accepting command socket connections"); 595 596 if (ZYGOTE_FORK_MODE) { 597 runForkMode(); 598 } else { 599 runSelectLoopMode(); →/dev/socket/zygote からの受信ループへ 600 } 601 602 closeServerSocket(); 603 } catch (MethodAndArgsCaller caller) { 604 caller.run(); 605 } catch (RuntimeException ex) { 606 Log.e(TAG, "Zygote died with exception", ex); 607 closeServerSocket(); 608 throw ex; 609 } 610 }
1. Launcher のアプリをタップ〜Activity Manager へ要求を投げるまで
packages/apps/Launcher2/src/com/android/launcher2/Launcher.java
1471 /** 1472 * Launches the intent referred by the clicked shortcut. 1473 * 1474 * @param v The view representing the clicked shortcut. 1475 */ 1476 public void onClick(View v) { 1477 Object tag = v.getTag(); 1478 if (tag instanceof ShortcutInfo) { 1479 // Open shortcut 1480 final Intent intent = ((ShortcutInfo) tag).intent; 1481 int[] pos = new int[2]; 1482 v.getLocationOnScreen(pos); 1483 intent.setSourceBounds(new Rect(pos[0], pos[1], 1484 pos[0] + v.getWidth(), pos[1] + v.getHeight())); 1485 startActivitySafely(intent, tag); 1486 } else if (tag instanceof FolderInfo) { 1487 handleFolderClick((FolderInfo) tag); 1488 } else if (v == mHandleView) { 1489 if (isAllAppsVisible()) { 1490 closeAllApps(true); 1491 } else { 1492 showAllApps(true); 1493 } 1494 } 1495 } 1496 1497 void startActivitySafely(Intent intent, Object tag) { 1498 intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); 1499 try { 1500 startActivity(intent); 1501 } catch (ActivityNotFoundException e) { 1502 Toast.makeText(this, R.string.activity_not_found, Toast.LENGTH_SHORT).show();
frameworks/base/core/java/android/app/Activity.java
2931 @Override 2932 public void startActivity(Intent intent) { 2933 startActivityForResult(intent, -1); 2934 } 2825 public void startActivityForResult(Intent intent, int requestCode) { 2826 if (mParent == null) { 2827 Instrumentation.ActivityResult ar = 2828 mInstrumentation.execStartActivity( 2829 this, mMainThread.getApplicationThread(), mToken, this, 2830 intent, requestCode); 2831 if (ar != null) { 2832 mMainThread.sendActivityResult( 2833 mToken, mEmbeddedID, requestCode, ar.getResultCode(), 2834 ar.getResultData()); 2835 }
frameworks/base/core/java/android/app/Instrumentation.java
1354 public ActivityResult execStartActivity( 1355 Context who, IBinder contextThread, IBinder token, Activity target, 1356 Intent intent, int requestCode) { 1357 IApplicationThread whoThread = (IApplicationThread) contextThread; : 1373 try { 1374 int result = ActivityManagerNative.getDefault() 1375 .startActivity(whoThread, intent, 1376 intent.resolveTypeIfNeeded(who.getContentResolver()), 1377 null, 0, token, target != null ? target.mEmbeddedID : null, 1378 requestCode, false, false); ↑稼動中の Activity Manager へ Binder による IPC 経由で要求を送出 1379 checkStartActivityResult(result, intent); 1380 } catch (RemoteException e) { 1381 } 1382 return null; 1383 }
frameworks/base/core/java/android/app/ActivityManagerNative.java
69 /** 70 * Retrieve the system's default/global activity manager. 71 */ 72 static public IActivityManager getDefault() 73 { 74 if (gDefault != null) { 75 //if (Config.LOGV) Log.v( 76 // "ActivityManager", "returning cur default = " + gDefault); 77 return gDefault; 78 } 79 IBinder b = ServiceManager.getService("activity"); 80 if (Config.LOGV) Log.v( 81 "ActivityManager", "default service binder = " + b); 82 gDefault = asInterface(b); 83 if (Config.LOGV) Log.v( 84 "ActivityManager", "default service = " + gDefault); 85 return gDefault; 86 }
2. Activity Manager が Zygote へプロセス生成要求を投げるまで
frameworks/base/services/java/com/android/server/am/ActivityManagerService.java
393 public ActivityStack mMainStack; : 2064 public final int startActivity(IApplicationThread caller, 2065 Intent intent, String resolvedType, Uri[] grantedUriPermissions, 2066 int grantedMode, IBinder resultTo, 2067 String resultWho, int requestCode, boolean onlyIfNeeded, 2068 boolean debug) { 2069 return mMainStack.startActivityMayWait(caller, intent, resolvedType, 2070 grantedUriPermissions, grantedMode, resultTo, resultWho, 2071 requestCode, onlyIfNeeded, debug, null, null); 2072 } 1265 public static final Context main(int factoryTest) { : 1278 ActivityManagerService m = thr.mService; 1279 mSelf = m; 1280 ActivityThread at = ActivityThread.systemMain(); 1281 mSystemThread = at; 1282 Context context = at.getSystemContext(); 1283 m.mContext = context; 1284 m.mFactoryTest = factoryTest; 1285 m.mMainStack = new ActivityStack(m, context, true); :
frameworks/base/services/java/com/android/server/am/ActivityStack.java
2387 final int startActivityMayWait(IApplicationThread caller, 2388 Intent intent, String resolvedType, Uri[] grantedUriPermissions, 2389 int grantedMode, IBinder resultTo, 2390 String resultWho, int requestCode, boolean onlyIfNeeded, 2391 boolean debug, WaitResult outResult, Configuration config) { 2392 // Refuse possible leaked file descriptors 2393 if (intent != null && intent.hasFileDescriptors()) { 2394 throw new IllegalArgumentException("File descriptors passed in Intent"); 2395 } 2396 2397 boolean componentSpecified = intent.getComponent() != null; 2398 2399 // Don't modify the client's object! 2400 intent = new Intent(intent); 2401 2402 // Collect information about the target of the Intent. 2403 ActivityInfo aInfo; 2404 try { 2405 ResolveInfo rInfo = 2406 AppGlobals.getPackageManager().resolveIntent( 2407 intent, resolvedType, 2408 PackageManager.MATCH_DEFAULT_ONLY 2409 | ActivityManagerService.STOCK_PM_FLAGS); 2410 aInfo = rInfo != null ? rInfo.activityInfo : null; 2411 } catch (RemoteException e) { 2412 aInfo = null; 2413 } 2414 2415 if (aInfo != null) { 2416 // Store the found target back into the intent, because now that 2417 // we have it we never want to do this again. For example, if the 2418 // user navigates back to this point in the history, we should 2419 // always restart the exact same activity. 2420 intent.setComponent(new ComponentName( 2421 aInfo.applicationInfo.packageName, aInfo.name)); 2422 2423 // Don't debug things in the system process 2424 if (debug) { 2425 if (!aInfo.processName.equals("system")) { 2426 mService.setDebugApp(aInfo.processName, true, false); 2427 } 2428 } 2429 } 2430 2431 synchronized (mService) { 2432 int callingPid; 2433 int callingUid; 2434 if (caller == null) { 2435 callingPid = Binder.getCallingPid(); 2436 callingUid = Binder.getCallingUid(); 2437 } else { 2438 callingPid = callingUid = -1; 2439 } 2440 2441 mConfigWillChange = config != null 2442 && mService.mConfiguration.diff(config) != 0; 2443 if (DEBUG_CONFIGURATION) Slog.v(TAG, 2444 "Starting activity when config will change = " + mConfigWillChange); 2445 2446 final long origId = Binder.clearCallingIdentity(); 2447 2448 if (mMainStack && aInfo != null && 2449 (aInfo.applicationInfo.flags&ApplicationInfo.FLAG;_CANT_SAVE_STATE) != 0) { 2450 // This may be a heavy-weight process! Check to see if we already 2451 // have another, different heavy-weight process running. : 2514 } 2515 2516 int res = startActivityLocked(caller, intent, resolvedType, 2517 grantedUriPermissions, grantedMode, aInfo, 2518 resultTo, resultWho, requestCode, callingPid, callingUid, 2519 onlyIfNeeded, componentSpecified);
1877 final int startActivityLocked(IApplicationThread caller, 1878 Intent intent, String resolvedType, 1879 Uri[] grantedUriPermissions, 1880 int grantedMode, ActivityInfo aInfo, IBinder resultTo, 1881 String resultWho, int requestCode, 1882 int callingPid, int callingUid, boolean onlyIfNeeded, 1883 boolean componentSpecified) { 1884 1885 int err = START_SUCCESS; 1886 1887 ProcessRecord callerApp = null; 1888 if (caller != null) { 1889 callerApp = mService.getRecordForAppLocked(caller); 1890 if (callerApp != null) { 1891 callingPid = callerApp.pid; 1892 callingUid = callerApp.info.uid; 1893 } else { 1894 Slog.w(TAG, "Unable to find app for caller " + caller 1895 + " (pid=" + callingPid + ") when starting: " 1896 + intent.toString()); 1897 err = START_PERMISSION_DENIED; 1898 } 1899 } 1900 1901 if (err == START_SUCCESS) { 1902 Slog.i(TAG, "Starting: " + intent + " from pid " 1903 + (callerApp != null ? callerApp.pid : callingPid)); 1904 } 1905 1906 ActivityRecord sourceRecord = null; 1907 ActivityRecord resultRecord = null; 1908 if (resultTo != null) { 1909 int index = indexOfTokenLocked(resultTo); 1910 if (DEBUG_RESULTS) Slog.v( 1911 TAG, "Sending result to " + resultTo + " (index " + index + ")"); 1912 if (index >= 0) { 1913 sourceRecord = (ActivityRecord)mHistory.get(index); 1914 if (requestCode >= 0 && !sourceRecord.finishing) { 1915 resultRecord = sourceRecord; 1916 } 1917 } 1918 } 1919 1920 int launchFlags = intent.getFlags(); 1921 1922 if ((launchFlags&Intent.FLAG;_ACTIVITY_FORWARD_RESULT) != 0 1923 && sourceRecord != null) { 1924 // Transfer the result target from the source activity to the new 1925 // one being started, including any failures. 1926 if (requestCode >= 0) { 1927 return START_FORWARD_AND_REQUEST_CONFLICT; 1928 } 1929 resultRecord = sourceRecord.resultTo; 1930 resultWho = sourceRecord.resultWho; 1931 requestCode = sourceRecord.requestCode; 1932 sourceRecord.resultTo = null; 1933 if (resultRecord != null) { 1934 resultRecord.removeResultsLocked( 1935 sourceRecord, resultWho, requestCode); 1936 } 1937 } : 1960 final int perm = mService.checkComponentPermission(aInfo.permission, callingPid, 1961 callingUid, aInfo.exported ? -1 : aInfo.applicationInfo.uid); 1962 if (perm != PackageManager.PERMISSION_GRANTED) { 1963 if (resultRecord != null) { 1964 sendActivityResultLocked(-1, 1965 resultRecord, resultWho, requestCode, 1966 Activity.RESULT_CANCELED, null); 1967 } 1968 String msg = "Permission Denial: starting " + intent.toString() 1969 + " from " + callerApp + " (pid=" + callingPid 1970 + ", uid=" + callingUid + ")" 1971 + " requires " + aInfo.permission; 1972 Slog.w(TAG, msg); 1973 throw new SecurityException(msg); 1974 } : 2002 ActivityRecord r = new ActivityRecord(mService, this, callerApp, callingUid, 2003 intent, resolvedType, aInfo, mService.mConfiguration, 2004 resultRecord, resultWho, requestCode, componentSpecified); : 2035 return startActivityUncheckedLocked(r, sourceRecord, 2036 grantedUriPermissions, grantedMode, onlyIfNeeded, true); 2037 }
2039 final int startActivityUncheckedLocked(ActivityRecord r, 2040 ActivityRecord sourceRecord, Uri[] grantedUriPermissions, 2041 int grantedMode, boolean onlyIfNeeded, boolean doResume) { : 2294 boolean newTask = false; 2295 2296 // Should this be considered a new task? 2297 if (r.resultTo == null && !addingToTask 2298 && (launchFlags&Intent.FLAG;_ACTIVITY_NEW_TASK) != 0) { 2299 // todo: should do better management of integers. 2300 mService.mCurTask++; 2301 if (mService.mCurTask <= 0) { 2302 mService.mCurTask = 1; 2303 } 2304 r.task = new TaskRecord(mService.mCurTask, r.info, intent, 2305 (r.info.flags&ActivityInfo.FLAG;_CLEAR_TASK_ON_LAUNCH) != 0); 2306 if (DEBUG_TASKS) Slog.v(TAG, "Starting new activity " + r 2307 + " in new task " + r.task); 2308 newTask = true; 2309 if (mMainStack) { 2310 mService.addRecentTaskLocked(r.task); 2311 } 2312 2313 } : 2383 startActivityLocked(r, newTask, doResume); 2384 return START_SUCCESS; 2385 }
1349 private final void startActivityLocked(ActivityRecord r, boolean newTask, 1350 boolean doResume) { : 1475 if (doResume) { 1476 resumeTopActivityLocked(null); 1477 } 1478 }
1051 final boolean resumeTopActivityLocked(ActivityRecord prev) { 1052 // Find the first activity that is not finishing. 1053 ActivityRecord next = topRunningActivityLocked(null); : 1343 startSpecificActivityLocked(next, true, true);
594 private final void startSpecificActivityLocked(ActivityRecord r, 595 boolean andResume, boolean checkConfig) { 596 // Is this activity's application already running? 597 ProcessRecord app = mService.getProcessRecordLocked(r.processName, 598 r.info.applicationInfo.uid); 599 600 if (r.launchTime == 0) { 601 r.launchTime = SystemClock.uptimeMillis(); 602 if (mInitialStartTime == 0) { 603 mInitialStartTime = r.launchTime; 604 } 605 } else if (mInitialStartTime == 0) { 606 mInitialStartTime = SystemClock.uptimeMillis(); 607 } 608 609 if (app != null && app.thread != null) { 610 try { 611 realStartActivityLocked(r, app, andResume, checkConfig); 612 return; 613 } catch (RemoteException e) { 614 Slog.w(TAG, "Exception when starting activity " 615 + r.intent.getComponent().flattenToShortString(), e); 616 } 617 618 // If a dead object exception was thrown -- fall through to 619 // restart the application. 620 } 621 622 mService.startProcessLocked(r.processName, r.info.applicationInfo, true, 0, 623 "activity", r.intent.getComponent(), false); 624 }
frameworks/base/services/java/com/android/server/am/ActivityManagerService.java
1724 final ProcessRecord startProcessLocked(String processName, 1725 ApplicationInfo info, boolean knownToBeDead, int intentFlags, 1726 String hostingType, ComponentName hostingName, boolean allowWhileBooting) { 1727 ProcessRecord app = getProcessRecordLocked(processName, info.uid); 1728 // We don't have to do anything more if: 1729 // (1) There is an existing application record; and 1730 // (2) The caller doesn't think it is dead, OR there is no thread 1731 // object attached to it so we know it couldn't have crashed; and 1732 // (3) There is a pid assigned to it, so it is either starting or 1733 // already running. : 1752 String hostingNameStr = hostingName != null 1753 ? hostingName.flattenToShortString() : null; 1781 if (app == null) { 1782 app = newProcessRecordLocked(null, info, processName); 1783 mProcessNames.put(processName, info.uid, app); 1784 } else { 1785 // If this is a new package in the process, add the package to the list 1786 app.addPackage(info.packageName); 1787 } : 1801 startProcessLocked(app, hostingType, hostingNameStr); 1802 return (app.pid != 0) ? app : null; 1803 }
478 /** 479 * All of the processes we currently have running organized by pid. 480 * The keys are the pid running the application. 481 * 482 * NOTE: This object is protected by its own lock, NOT the global 483 * activity manager lock! 484 */ 485 final SparseArray<ProcessRecord> mPidsSelfLocked 486 = new SparseArray<ProcessRecord>(); : 1809 private final void startProcessLocked(ProcessRecord app, 1810 String hostingType, String hostingNameStr) { : 1828 try { 1829 int uid = app.info.uid; 1830 int[] gids = null; 1831 try { 1832 gids = mContext.getPackageManager().getPackageGids( 1833 app.info.packageName); 1834 } catch (PackageManager.NameNotFoundException e) { 1835 Slog.w(TAG, "Unable to retrieve gids", e); 1836 } : 1848 int debugFlags = 0; 1849 if ((app.info.flags & ApplicationInfo.FLAG_DEBUGGABLE) != 0) { 1850 debugFlags |= Zygote.DEBUG_ENABLE_DEBUGGER; 1851 } 1852 // Run the app in safe mode if its manifest requests so or the 1853 // system is booted in safe mode. 1854 if ((app.info.flags & ApplicationInfo.FLAG_VM_SAFE_MODE) != 0 || 1855 Zygote.systemInSafeMode == true) { 1856 debugFlags |= Zygote.DEBUG_ENABLE_SAFEMODE; 1857 } 1858 if ("1".equals(SystemProperties.get("debug.checkjni"))) { 1859 debugFlags |= Zygote.DEBUG_ENABLE_CHECKJNI; 1860 } 1861 if ("1".equals(SystemProperties.get("debug.assert"))) { 1862 debugFlags |= Zygote.DEBUG_ENABLE_ASSERT; 1863 } 1864 1865 // Start the process. It will either succeed and return a result containing 1866 // the PID of the new process, or else throw a RuntimeException. 1867 Process.ProcessStartResult startResult = Process.start("android.app.ActivityThread", 1868 app.processName, uid, uid, gids, debugFlags, null); →クラス名が "android.app.ActivityThread" の決め打ちであることに注意 : 1908 if (startResult.pid == 0 || startResult.pid == MY_PID) { 1909 // Processes are being emulated with threads. 1910 app.pid = MY_PID; 1911 app.removed = false; 1912 mStartingProcesses.add(app); 1913 } else { 1914 app.pid = startResult.pid; 1915 app.usingWrapper = startResult.usingWrapper; 1916 app.removed = false; 1917 synchronized (mPidsSelfLocked) { 1918 this.mPidsSelfLocked.put(startResult.pid, app); →当該アプリの ProcessRecord を mPidsSelfLocked テーブルに登録 1919 Message msg = mHandler.obtainMessage(PROC_START_TIMEOUT_MSG); 1920 msg.obj = app; 1921 mHandler.sendMessageDelayed(msg, startResult.usingWrapper 1922 ? PROC_START_TIMEOUT_WITH_WRAPPER : PROC_START_TIMEOUT); 1923 } 1924 } :
frameworks/base/core/java/android/os/Process.java
236 /** 237 * Start a new process. 238 * 239 * If processes are enabled, a new process is created and the 240 * static main() function of a processClass is executed there. 241 * The process will continue running after this function returns. 242 * 243 * If processes are not enabled, a new thread in the caller's 244 * process is created and main() of processClass called there. 245 * 246 * The niceName parameter, if not an empty string, is a custom name to 247 * give to the process instead of using processClass. This allows you to 248 * make easily identifyable processes even if you are using the same base 249 * processClass to start them. 250 * 251 * @param processClass The class to use as the process's main entry 252 * point. 253 * @param niceName A more readable name to use for the process. 254 * @param uid The user-id under which the process will run. 255 * @param gid The group-id under which the process will run. 256 * @param gids Additional group-ids associated with the process. 257 * @param enableDebugger True if debugging should be enabled for this process. 258 * @param zygoteArgs Additional arguments to supply to the zygote process. 259 * 260 * @return An object that describes the result of the attempt to start the process. 261 * @throws RuntimeException on fatal start failure 262 * 263 * {@hide} 264 */ 265 public static final ProcessStartResult start(final String processClass, 266 final String niceName, 267 int uid, int gid, int[] gids, 268 int debugFlags, 269 String[] zygoteArgs) 270 { 271 if (supportsProcesses()) { 272 try { 273 return startViaZygote(processClass, niceName, uid, gid, gids, 274 debugFlags, zygoteArgs); 275 } catch (ZygoteStartFailedEx ex) { 276 Log.e(LOG_TAG, 277 "Starting VM process through Zygote failed"); 278 throw new RuntimeException( 279 "Starting VM process through Zygote failed", ex); 280 } 281 } else { 282 // Running in single-process mode 283 284 Runnable runnable = new Runnable() { 285 public void run() { 286 Process.invokeStaticMain(processClass); 287 } 288 }; 289 290 // Thread constructors must not be called with null names (see spec). 291 if (niceName != null) { 292 new Thread(runnable, niceName).start(); 293 } else { 294 new Thread(runnable).start(); 295 } 296 return new ProcessStartResult(); 297 } 298 }
478 /** 479 * Starts a new process via the zygote mechanism. 480 * 481 * @param processClass Class name whose static main() to run 482 * @param niceName 'nice' process name to appear in ps 483 * @param uid a POSIX uid that the new process should setuid() to 484 * @param gid a POSIX gid that the new process shuold setgid() to 485 * @param gids null-ok; a list of supplementary group IDs that the 486 * new process should setgroup() to. 487 * @param enableDebugger True if debugging should be enabled for this process. 488 * @param extraArgs Additional arguments to supply to the zygote process. 489 * @return An object that describes the result of the attempt to start the process. 490 * @throws ZygoteStartFailedEx if process start failed for any reason 491 */ 492 private static ProcessStartResult startViaZygote(final String processClass, 493 final String niceName, 494 final int uid, final int gid, 495 final int[] gids, 496 int debugFlags, 497 String[] extraArgs) 498 throws ZygoteStartFailedEx { 499 synchronized(Process.class) { 500 ArrayList<String> argsForZygote = new ArrayList≶String>(); 501 502 // --runtime-init, --setuid=, --setgid=, 503 // and --setgroups= must go first ↓zygote ソケットへ送る電文を編集 504 argsForZygote.add("--runtime-init"); 505 argsForZygote.add("--setuid=" + uid); 506 argsForZygote.add("--setgid=" + gid); 507 if ((debugFlags & Zygote.DEBUG_ENABLE_SAFEMODE) != 0) { 508 argsForZygote.add("--enable-safemode"); 509 } 510 if ((debugFlags & Zygote.DEBUG_ENABLE_DEBUGGER) != 0) { 511 argsForZygote.add("--enable-debugger"); 512 } 513 if ((debugFlags & Zygote.DEBUG_ENABLE_CHECKJNI) != 0) { 514 argsForZygote.add("--enable-checkjni"); 515 } 516 if ((debugFlags & Zygote.DEBUG_ENABLE_ASSERT) != 0) { 517 argsForZygote.add("--enable-assert"); 518 } 519 520 //TODO optionally enable debuger 521 //argsForZygote.add("--enable-debugger"); 522 523 // --setgroups is a comma-separated list 524 if (gids != null && gids.length > 0) { 525 StringBuilder sb = new StringBuilder(); 526 sb.append("--setgroups="); 527 528 int sz = gids.length; 529 for (int i = 0; i < sz; i++) { 530 if (i != 0) { 531 sb.append(','); 532 } 533 sb.append(gids[i]); 534 } 535 536 argsForZygote.add(sb.toString()); 537 } 538 539 if (niceName != null) { 540 argsForZygote.add("--nice-name=" + niceName); 541 } 542 543 argsForZygote.add(processClass); 544 545 if (extraArgs != null) { 546 for (String arg : extraArgs) { 547 argsForZygote.add(arg); 548 } 549 } 550 551 return zygoteSendArgsAndGetResult(argsForZygote); 552 } 553 }
414 /** 415 * Sends an argument list to the zygote process, which starts a new child 416 * and returns the child's pid. Please note: the present implementation 417 * replaces newlines in the argument list with spaces. 418 * @param args argument list 419 * @return An object that describes the result of the attempt to start the process. 420 * @throws ZygoteStartFailedEx if process start failed for any reason 421 */ 422 private static ProcessStartResult zygoteSendArgsAndGetResult(ArrayList<String> args) 423 throws ZygoteStartFailedEx { 424 openZygoteSocketIfNeeded(); 425 426 try { 427 /** 428 * See com.android.internal.os.ZygoteInit.readArgumentList() 429 * Presently the wire format to the zygote process is: 430 * a) a count of arguments (argc, in essence) 431 * b) a number of newline-separated argument strings equal to count 432 * 433 * After the zygote process reads these it will write the pid of 434 * the child or -1 on failure, followed by boolean to 435 * indicate whether a wrapper process was used. 436 */ 437 ↓zygote ソケットへの書き込み 438 sZygoteWriter.write(Integer.toString(args.size())); 439 sZygoteWriter.newLine(); 440 441 int sz = args.size(); 442 for (int i = 0; i < sz; i++) { 443 String arg = args.get(i); 444 if (arg.indexOf('\n') >= 0) { 445 throw new ZygoteStartFailedEx( 446 "embedded newlines not allowed"); 447 } 448 sZygoteWriter.write(arg); 449 sZygoteWriter.newLine(); 450 } 451 452 sZygoteWriter.flush();
3. 要求を受け取った Zygote がプロセスを fork するまで
frameworks/base/core/java/com/android/internal/os/ZygoteInit.java
650 /** 651 * Runs the zygote process's select loop. Accepts new connections as 652 * they happen, and reads commands from connections one spawn-request's 653 * worth at a time. 654 * 655 * @throws MethodAndArgsCaller in a child process when a main() should 656 * be executed. 657 */ 658 private static void runSelectLoopMode() throws MethodAndArgsCaller { 659 ArrayList<FileDescriptor> fds = new ArrayList(); 660 ArrayList<ZygoteConnection> peers = new ArrayList(); 661 FileDescriptor[] fdArray = new FileDescriptor[4]; 662 663 fds.add(sServerSocket.getFileDescriptor()); 664 peers.add(null); 665 666 int loopCount = GC_LOOP_COUNT; 667 while (true) { 668 int index; : 687 try { 688 fdArray = fds.toArray(fdArray); 689 index = selectReadable(fdArray); 690 } catch (IOException ex) { 691 throw new RuntimeException("Error in select()", ex); 692 } 693 694 if (index < 0) { 695 throw new RuntimeException("Error in select()"); 696 } else if (index == 0) { 697 ZygoteConnection newPeer = acceptCommandPeer(); 698 peers.add(newPeer); 699 fds.add(newPeer.getFileDesciptor()); 700 } else { 701 boolean done; 702 done = peers.get(index).runOnce(); 703 704 if (done) { 705 peers.remove(index); 706 fds.remove(index); 707 } 708 } 709 } 710 }
195 /** 196 * Waits for and accepts a single command connection. Throws 197 * RuntimeException on failure. 198 */ 199 private static ZygoteConnection acceptCommandPeer() { 200 try { 201 return new ZygoteConnection(sServerSocket.accept()); 202 } catch (IOException ex) { 203 throw new RuntimeException( 204 "IOException during accept()", ex); 205 } 206 }
frameworks/base/core/java/com/android/internal/os/ZygoteConnectionjava
39 /** 40 * A connection that can make spawn requests. 41 */ 42 class ZygoteConnection { 43 private static final String TAG = "Zygote"; 44 45 /** a prototype instance for a future List.toArray() */ 46 private static final int[][] intArray2d = new int[0][0]; 47 48 /** 49 * {@link android.net.LocalSocket#setSoTimeout} value for connections. 50 * Effectively, the amount of time a requestor has between the start of 51 * the request and the completed request. The select-loop mode Zygote 52 * doesn't have the logic to return to the select loop in the middle of 53 * a request, so we need to time out here to avoid being denial-of-serviced. 54 */ 55 private static final int CONNECTION_TIMEOUT_MILLIS = 1000; 56 57 /** max number of arguments that a connection can specify */ 58 private static final int MAX_ZYGOTE_ARGC=1024; 59 60 /** 61 * The command socket. 62 * 63 * mSocket is retained in the child process in "peer wait" mode, so 64 * that it closes when the child process terminates. In other cases, 65 * it is closed in the peer. 66 */ 67 private final LocalSocket mSocket; 68 private final DataOutputStream mSocketOutStream; 69 private final BufferedReader mSocketReader; 70 private final Credentials peer; 71 72 /** 73 * A long-lived reference to the original command socket used to launch 74 * this peer. If "peer wait" mode is specified, the process that requested 75 * the new VM instance intends to track the lifetime of the spawned instance 76 * via the command socket. In this case, the command socket is closed 77 * in the Zygote and placed here in the spawned instance so that it will 78 * not be collected and finalized. This field remains null at all times 79 * in the original Zygote process, and in all spawned processes where 80 * "peer-wait" mode was not requested. 81 */ 82 private static LocalSocket sPeerWaitSocket = null; 83 84 /** 85 * Constructs instance from connected socket. 86 * 87 * @param socket non-null; connected socket 88 * @throws IOException 89 */ 90 ZygoteConnection(LocalSocket socket) throws IOException { 91 mSocket = socket; 92 93 mSocketOutStream 94 = new DataOutputStream(socket.getOutputStream()); 95 96 mSocketReader = new BufferedReader( 97 new InputStreamReader(socket.getInputStream()), 256); 98 99 mSocket.setSoTimeout(CONNECTION_TIMEOUT_MILLIS); 100 101 try { 102 peer = mSocket.getPeerCredentials(); 103 } catch (IOException ex) { 104 Log.e(TAG, "Cannot read peer credentials", ex); 105 throw ex; 106 } 107 }
155 /** 156 * Reads one start command from the command socket. If successful, 157 * a child is forked and a {@link ZygoteInit.MethodAndArgsCaller} 158 * exception is thrown in that child while in the parent process, 159 * the method returns normally. On failure, the child is not 160 * spawned and messages are printed to the log and stderr. Returns 161 * a boolean status value indicating whether an end-of-file on the command 162 * socket has been encountered. 163 * 164 * @return false if command socket should continue to be read from, or 165 * true if an end-of-file has been encountered. 166 * @throws ZygoteInit.MethodAndArgsCaller trampoline to invoke main() 167 * method in child process 168 */ 169 boolean runOnce() throws ZygoteInit.MethodAndArgsCaller { 170 171 String args[]; 172 Arguments parsedArgs = null; 173 FileDescriptor[] descriptors; 174 175 try { 176 args = readArgumentList(); 177 descriptors = mSocket.getAncillaryFileDescriptors(); 178 } catch (IOException ex) { 179 Log.w(TAG, "IOException on command socket " + ex.getMessage()); 180 closeSocket(); 181 return true; 182 } 183 184 if (args == null) { 185 // EOF reached. 186 closeSocket(); 187 return true; 188 } 189 190 /** the stderr of the most recent request, if avail */ 191 PrintStream newStderr = null; 192 193 if (descriptors != null && descriptors.length >= 3) { 194 newStderr = new PrintStream( 195 new FileOutputStream(descriptors[2])); 196 } 197 198 int pid = -1; 199 FileDescriptor childPipeFd = null; 200 FileDescriptor serverPipeFd = null; 201 202 try { 203 parsedArgs = new Arguments(args); 204 205 applyUidSecurityPolicy(parsedArgs, peer); →perr プロセスの uid と電文上の uid, gid 指定の関係をチェック 206 applyRlimitSecurityPolicy(parsedArgs, peer); 207 applyCapabilitiesSecurityPolicy(parsedArgs, peer); 208 applyInvokeWithSecurityPolicy(parsedArgs, peer); 209 210 applyDebuggerSystemProperty(parsedArgs); 211 applyInvokeWithSystemProperty(parsedArgs); 212 213 int[][] rlimits = null; 214 215 if (parsedArgs.rlimits != null) { 216 rlimits = parsedArgs.rlimits.toArray(intArray2d); 217 } 218 219 if (parsedArgs.runtimeInit && parsedArgs.invokeWith != null) { 220 FileDescriptor[] pipeFds = new FileDescriptor[2]; 221 ZygoteInit.pipe(pipeFds); 222 childPipeFd = pipeFds[1]; 223 serverPipeFd = pipeFds[0]; 224 ZygoteInit.setCloseOnExec(serverPipeFd, true); 225 } 226 227 pid = Zygote.forkAndSpecialize(parsedArgs.uid, parsedArgs.gid, 228 parsedArgs.gids, parsedArgs.debugFlags, rlimits); →ネイティブコードでプロセスを fork 229 } catch (IOException ex) { 230 logAndPrintError(newStderr, "Exception creating pipe", ex); 231 } catch (IllegalArgumentException ex) { 232 logAndPrintError(newStderr, "Invalid zygote arguments", ex); 233 } catch (ZygoteSecurityException ex) { 234 logAndPrintError(newStderr, 235 "Zygote security policy prevents request: ", ex); 236 } 237 238 try { 239 if (pid == 0) { 240 // in child 241 ZygoteInit.closeDescriptorQuietly(serverPipeFd); 242 serverPipeFd = null; 243 handleChildProc(parsedArgs, descriptors, childPipeFd, newStderr); 244 245 // should never get here, the child is expected to either 246 // throw ZygoteInit.MethodAndArgsCaller or exec(). 247 return true; 248 } else { 249 // in parent...pid of < 0 means failure 250 ZygoteInit.closeDescriptorQuietly(childPipeFd); 251 childPipeFd = null; 252 return handleParentProc(pid, descriptors, serverPipeFd, parsedArgs); 253 } 254 } finally { 255 ZygoteInit.closeDescriptorQuietly(childPipeFd); 256 ZygoteInit.closeDescriptorQuietly(serverPipeFd); 257 } 258 }
558 /** 559 * Applies zygote security policy per bugs #875058 and #1082165. 560 * Based on the credentials of the process issuing a zygote command: 561 * 562 * - uid 0 (root) may specify any uid, gid, and setgroups() list 563 * - uid 1000 (Process.SYSTEM_UID) may specify any uid > 1000 in normal 564 * operation. It may also specify any gid and setgroups() list it chooses. 565 * In factory test mode, it may specify any UID. 566 * - Any other uid may not specify any uid, gid, or setgroups list. The 567 * uid and gid will be inherited from the requesting process. 569 * 570 * @param args non-null; zygote spawner arguments 571 * @param peer non-null; peer credentials 572 * @throws ZygoteSecurityException 573 */ 574 private static void applyUidSecurityPolicy(Arguments args, Credentials peer) 575 throws ZygoteSecurityException { 576 577 int peerUid = peer.getUid(); 578 579 if (peerUid == 0) { 580 // Root can do what it wants 581 } else if (peerUid == Process.SYSTEM_UID ) { 582 // System UID is restricted, except in factory test mode 583 String factoryTest = SystemProperties.get("ro.factorytest"); 584 boolean uidRestricted; 585 586 /* In normal operation, SYSTEM_UID can only specify a restricted 587 * set of UIDs. In factory test mode, SYSTEM_UID may specify any uid. 588 */ 589 uidRestricted 590 = !(factoryTest.equals("1") || factoryTest.equals("2")); 591 592 if (uidRestricted 593 && args.uidSpecified && (args.uid < Process.SYSTEM_UID)) { 594 throw new ZygoteSecurityException( 595 "System UID may not launch process with UID < " 596 + Process.SYSTEM_UID); 597 } 598 } else { 599 // Everything else 600 if (args.uidSpecified || args.gidSpecified 601 || args.gids != null) { 602 throw new ZygoteSecurityException( 603 "App UIDs may not specify uid's or gid's"); 604 } → peer プロセスの uid が root でも system でもない場合は 電文に uid, gid の指定があってはならない。 605 } 606 607 // If not otherwise specified, uid and gid are inherited from peer 608 if (!args.uidSpecified) { 609 args.uid = peer.getUid(); 610 args.uidSpecified = true; 611 } 612 if (!args.gidSpecified) { 613 args.gid = peer.getGid(); 614 args.gidSpecified = true; 615 } 616 }
4. fork されたプロセスが Activity Manager へ対象アプリ情報を照会するまで
frameworks/base/core/java/com/android/internal/os/ZygoteConnection.java
760 /** 761 * Handles post-fork setup of child proc, closing sockets as appropriate, 762 * reopen stdio as appropriate, and ultimately throwing MethodAndArgsCaller 763 * if successful or returning if failed. 764 * 765 * @param parsedArgs non-null; zygote args 766 * @param descriptors null-ok; new file descriptors for stdio if available. 767 * @param pipeFd null-ok; pipe for communication back to Zygote. 768 * @param newStderr null-ok; stream to use for stderr until stdio 769 * is reopened. 770 * 771 * @throws ZygoteInit.MethodAndArgsCaller on success to 772 * trampoline to code that invokes static main. 773 */ 774 private void handleChildProc(Arguments parsedArgs, 775 FileDescriptor[] descriptors, FileDescriptor pipeFd, PrintStream newStderr) 776 throws ZygoteInit.MethodAndArgsCaller { : 792 closeSocket(); 793 ZygoteInit.closeServerSocket(); : 814 if (parsedArgs.runtimeInit) { 815 if (parsedArgs.invokeWith != null) { 816 WrapperInit.execApplication(parsedArgs.invokeWith, 817 parsedArgs.niceName, pipeFd, parsedArgs.remainingArgs); 818 } else { 819 RuntimeInit.zygoteInit(parsedArgs.remainingArgs); 820 } 821 } :
frameworks/base/core/java/com/android/internal/os/RuntimeInit.java
244 /** 245 * The main function called when started through the zygote process. This 246 * could be unified with main(), if the native code in finishInit() 247 * were rationalized with Zygote startup. 248 * 249 * Current recognized args: 251 * - [--] <start class name> <args> 253 * 254 * @param argv arg strings 255 */ 256 public static final void zygoteInit(String[] argv) 257 throws ZygoteInit.MethodAndArgsCaller { 258 if (DEBUG) Slog.d(TAG, "RuntimeInit: Starting application from zygote"); 259 260 redirectLogStreams(); 261 262 commonInit(); 263 zygoteInitNative(); 264 265 applicationInit(argv); 266 }
285 private static void applicationInit(String[] argv) 286 throws ZygoteInit.MethodAndArgsCaller { 287 // We want to be fairly aggressive about heap utilization, to avoid 288 // holding on to a lot of memory that isn't needed. 289 VMRuntime.getRuntime().setTargetHeapUtilization(0.75f); 290 291 final Arguments args; 292 try { 293 args = new Arguments(argv); 294 } catch (IllegalArgumentException ex) { 295 Slog.e(TAG, ex.getMessage()); 296 // let the process exit 297 return; 298 } 299 300 // Remaining arguments are passed to the start class's static main 301 invokeStaticMain(args.startClass, args.startArgs); 302 }
177 /** 178 * Invokes a static "main(argv[]) method on class "className". 179 * Converts various failing exceptions into RuntimeExceptions, with 180 * the assumption that they will then cause the VM instance to exit. 181 * 182 * @param className Fully-qualified class name 183 * @param argv Argument vector for main() 184 */ 185 private static void invokeStaticMain(String className, String[] argv) 186 throws ZygoteInit.MethodAndArgsCaller { 187 Class cl; 188 189 try { 190 cl = Class.forName(className); 191 } catch (ClassNotFoundException ex) { 192 throw new RuntimeException( 193 "Missing class when invoking static main " + className, 194 ex); 195 } 196 197 Method m; 198 try { 199 m = cl.getMethod("main", new Class[] { String[].class }); 200 } catch (NoSuchMethodException ex) { 201 throw new RuntimeException( 202 "Missing static main on " + className, ex); 203 } catch (SecurityException ex) { 204 throw new RuntimeException( 205 "Problem getting static main on " + className, ex); 206 } 207 208 int modifiers = m.getModifiers(); 209 if (! (Modifier.isStatic(modifiers) && Modifier.isPublic(modifiers))) { 210 throw new RuntimeException( 211 "Main method is not public and static on " + className); 212 } 213 214 /* 215 * This throw gets caught in ZygoteInit.main(), which responds 216 * by invoking the exception's run() method. This arrangement 217 * clears up all the stack frames that were required in setting 218 * up the process. 219 */ 220 throw new ZygoteInit.MethodAndArgsCaller(m, argv); 221 }
frameworks/base/core/java/com/android/internal/os/ZygoteInit.java
563 public static void main(String argv[]) { 564 try { 565 VMRuntime.getRuntime().setMinimumHeapSize(5 * 1024 * 1024); 566 567 // Start profiling the zygote initialization. 568 SamplingProfilerIntegration.start(); 569 570 registerZygoteSocket(); 571 EventLog.writeEvent(LOG_BOOT_PROGRESS_PRELOAD_START, 572 SystemClock.uptimeMillis()); 573 preload(); 574 EventLog.writeEvent(LOG_BOOT_PROGRESS_PRELOAD_END, 575 SystemClock.uptimeMillis()); 576 577 // Finish profiling the zygote initialization. 578 SamplingProfilerIntegration.writeZygoteSnapshot(); 579 580 // Do an initial gc to clean up after startup 581 gc(); 582 583 // If requested, start system server directly from Zygote 584 if (argv.length != 2) { 585 throw new RuntimeException(argv[0] + USAGE_STRING); 586 } 587 588 if (argv[1].equals("start-system-server")) { 589 startSystemServer(); 590 } else if (!argv[1].equals("")) { 591 throw new RuntimeException(argv[0] + USAGE_STRING); 592 } 593 594 Log.i(TAG, "Accepting command socket connections"); 595 596 if (ZYGOTE_FORK_MODE) { 597 runForkMode(); 598 } else { 599 runSelectLoopMode(); 600 } 601 602 closeServerSocket(); 603 } catch (MethodAndArgsCaller caller) { 604 caller.run(); 605 } catch (RuntimeException ex) { 606 Log.e(TAG, "Zygote died with exception", ex); 607 closeServerSocket(); 608 throw ex; 609 } 610 }
frameworks/base/core/java/android/app/ActivityThread.java
3665 public static final void main(String[] args) { 3666 SamplingProfilerIntegration.start(); 3667 3668 Process.setArgV0("<pre-initialized>"); 3669 3670 Looper.prepareMainLooper(); 3671 if (sMainThreadHandler == null) { 3672 sMainThreadHandler = new Handler(); 3673 } 3674 3675 ActivityThread thread = new ActivityThread(); 3676 thread.attach(false); →現プロセスに所定のアプリのコードをロードし実行する 3677 3678 if (false) { 3679 Looper.myLooper().setMessageLogging(new 3680 LogPrinter(Log.DEBUG, "ActivityThread")); 3681 } 3682 3683 Looper.loop(); 3684 3685 if (Process.supportsProcesses()) { 3686 throw new RuntimeException("Main thread loop unexpectedly exited"); 3687 } 3688 3689 thread.detach(); 3690 String name = (thread.mInitialApplication != null) 3691 ? thread.mInitialApplication.getPackageName() 3692 : "<unknown>"; 3693 Slog.i(TAG, "Main thread of " + name + " is now exiting"); 3694 } 3695 }
109 /** 110 * This manages the execution of the main thread in an 111 * application process, scheduling and executing activities, 112 * broadcasts, and other operations on it as the activity 113 * manager requests. 114 * 116 */ 117 public final class ActivityThread { 118 static final String TAG = "ActivityThread"; : 137 final ApplicationThread mAppThread = new ApplicationThread(); : 3590 private final void attach(boolean system) { 3591 sThreadLocal.set(this); 3592 mSystemThread = system; 3593 if (!system) { 3594 ViewRoot.addFirstDrawHandler(new Runnable() { 3595 public void run() { 3596 ensureJitEnabled(); 3597 } 3598 }); 3599 android.ddm.DdmHandleAppName.setAppName("<pre-initialized>"); 3600 RuntimeInit.setApplicationObject(mAppThread.asBinder()); 3601 IActivityManager mgr = ActivityManagerNative.getDefault(); 3602 try { 3603 mgr.attachApplication(mAppThread); → 本プロセス用のアプリの情報を Activity Manager に要求 3604 } catch (RemoteException ex) { 3605 } 3606 } :
5. Activity Manager が新規プロセスに起動対象アプリ情報を渡すまで
frameworks/base/services/java/com/android/server/am/ActivityManagerService.java
3638 public final void attachApplication(IApplicationThread thread) { 3639 synchronized (this) { 3640 int callingPid = Binder.getCallingPid(); 3641 final long origId = Binder.clearCallingIdentity(); 3642 attachApplicationLocked(thread, callingPid); 3643 Binder.restoreCallingIdentity(origId); 3644 } 3645 }
143 public final class ActivityManagerService extends ActivityManagerNative 144 implements Watchdog.Monitor, BatteryStatsImpl.BatteryCallback { 145 static final String TAG = "ActivityManager"; 146 static final boolean DEBUG = false; : 389 static final int MY_PID = Process.myPid(); : 478 /** 479 * All of the processes we currently have running organized by pid. 480 * The keys are the pid running the application. 481 * 482 * NOTE: This object is protected by its own lock, NOT the global 483 * activity manager lock! 484 */ 485 final SparseArray<ProcessRecord> mPidsSelfLocked 486 = new SparseArray<ProcessRecord>(); : 3417 private final boolean attachApplicationLocked(IApplicationThread thread, 3418 int pid) { 3419 3420 // Find the application record that is being attached... either via 3421 // the pid if we are running in multiple processes, or just pull the 3422 // next app record if we are emulating process with anonymous threads. 3423 ProcessRecord app; 3424 if (pid != MY_PID && pid >= 0) { 3425 synchronized (mPidsSelfLocked) { 3426 app = mPidsSelfLocked.get(pid); →mPidsSelfLocked テーブルに登録済みの当該 ProcessRecord を取得 3427 } 3428 } else if (mStartingProcesses.size() > 0) { 3429 app = mStartingProcesses.remove(0); 3430 app.setPid(pid); 3431 } else { 3432 app = null; 3433 } 3434 3435 if (app == null) { 3436 Slog.w(TAG, "No pending application record for pid " + pid 3437 + " (IApplicationThread " + thread + "); dropping process"); 3438 EventLog.writeEvent(EventLogTags.AM_DROP_PROCESS, pid); 3439 if (pid > 0 && pid != MY_PID) { 3440 Process.killProcess(pid); 3441 } else { 3442 try { 3443 thread.scheduleExit(); 3444 } catch (Exception e) { 3445 // Ignore exceptions. 3446 } 3447 } 3448 return false; 3449 } : 3457 // Tell the process all about itself. 3458 3459 if (localLOGV) Slog.v( 3460 TAG, "Binding process pid " + pid + " to record " + app); 3461 3462 String processName = app.processName; 3463 try { 3464 thread.asBinder().linkToDeath(new AppDeathRecipient( 3465 app, pid, thread), 0); 3466 } catch (RemoteException e) { 3467 app.resetPackageList(); 3468 startProcessLocked(app, "link fail", processName); 3469 return false; 3470 } : 3474 app.thread = thread; 3475 app.curAdj = app.setAdj = -100; 3476 app.curSchedGroup = Process.THREAD_GROUP_DEFAULT; 3477 app.setSchedGroup = Process.THREAD_GROUP_BG_NONINTERACTIVE; 3478 app.forcingToForeground = null; 3479 app.foregroundServices = false; 3480 app.debugging = false; : 3484 boolean normalMode = mProcessesReady || isAllowedWhileBooting(app.info); 3485 List providers = normalMode ? generateApplicationProvidersLocked(app) : null; : 3522 thread.bindApplication(processName, app.instrumentationInfo != null 3523 ? app.instrumentationInfo : app.info, providers, 3524 app.instrumentationClass, app.instrumentationProfileFile, 3525 app.instrumentationArguments, app.instrumentationWatcher, testMode, 3526 isRestrictedBackupMode || !normalMode, 3527 mConfiguration, getCommonServicesLocked()); 3528 updateLruProcessLocked(app, false, true); 3529 app.lastRequestedGc = app.lastLowMemory = SystemClock.uptimeMillis(); 3530 } catch (Exception e) { :
6. 新プロセスが Activity Manager からの情報をもとにアプリを起動するまで
frameworks/base/core/java/android/app/ActivityThread.java
367 private final class ApplicationThread extends ApplicationThreadNative { : 535 public final void bindApplication(String processName, 536 ApplicationInfo appInfo, List<ProviderInfo> providers, 537 ComponentName instrumentationName, String profileFile, 538 Bundle instrumentationArgs, IInstrumentationWatcher instrumentationWatcher, 539 int debugMode, boolean isRestrictedBackupMode, Configuration config, 540 Map<String, IBinder> services) { 541 542 if (services != null) { 543 // Setup the service cache in the ServiceManager 544 ServiceManager.initServiceCache(services); 545 } 546 547 AppBindData data = new AppBindData(); 548 data.processName = processName; 549 data.appInfo = appInfo; 550 data.providers = providers; 551 data.instrumentationName = instrumentationName; 552 data.profileFile = profileFile; 553 data.instrumentationArgs = instrumentationArgs; 554 data.instrumentationWatcher = instrumentationWatcher; 555 data.debugMode = debugMode; 556 data.restrictedBackupMode = isRestrictedBackupMode; 557 data.config = config; 558 queueOrSendMessage(H.BIND_APPLICATION, data); 559 } : 323 private static final class AppBindData { 324 LoadedApk info; 325 String processName; 326 ApplicationInfo appInfo; 327 List<ProviderInfo> providers; 328 ComponentName instrumentationName; 329 String profileFile; 330 Bundle instrumentationArgs; 331 IInstrumentationWatcher instrumentationWatcher; 332 int debugMode; 333 boolean restrictedBackupMode; 334 Configuration config; 335 boolean handlingProfiling; 336 public String toString() { 337 return "AppBindData{appInfo=" + appInfo + "}"; 338 } 339 }
1504 // if the thread hasn't started yet, we don't have the handler, so just 1505 // save the messages until we're ready. 1506 private final void queueOrSendMessage(int what, Object obj) { 1507 queueOrSendMessage(what, obj, 0, 0); 1508 } 1514 private final void queueOrSendMessage(int what, Object obj, int arg1, int arg2) { 1515 synchronized (this) { 1516 if (DEBUG_MESSAGES) Slog.v( 1517 TAG, "SCHEDULE " + what + " " + mH.codeToString(what) 1518 + ": " + arg1 + " / " + obj); 1519 Message msg = Message.obtain(); 1520 msg.what = what; 1521 msg.obj = obj; 1522 msg.arg1 = arg1; 1523 msg.arg2 = arg2; 1524 mH.sendMessage(msg); 1525 } 1526 } 923 public void handleMessage(Message msg) { 924 if (DEBUG_MESSAGES) Slog.v(TAG, ">>> handling: " + msg.what); 925 switch (msg.what) { 926 case LAUNCH_ACTIVITY: { 927 ActivityClientRecord r = (ActivityClientRecord)msg.obj; 928 929 r.packageInfo = getPackageInfoNoCheck( 930 r.activityInfo.applicationInfo); 931 handleLaunchActivity(r, null); 932 } break; : 967 case BIND_APPLICATION: 968 AppBindData data = (AppBindData)msg.obj; 969 handleBindApplication(data); 970 break; :
323 private static final class AppBindData { 324 LoadedApk info; 325 String processName; 326 ApplicationInfo appInfo; 327 List<ProviderInfo> providers; 328 ComponentName instrumentationName; 329 String profileFile; 330 Bundle instrumentationArgs; 331 IInstrumentationWatcher instrumentationWatcher; 332 int debugMode; 333 boolean restrictedBackupMode; 334 Configuration config; 335 boolean handlingProfiling; 336 public String toString() { 337 return "AppBindData{appInfo=" + appInfo + "}"; 338 } 339 } : 117 public final class ActivityThread { 118 static final String TAG = "ActivityThread"; : 152 Application mInitialApplication; : 158 Instrumentation mInstrumentation; : 3121 private final void handleBindApplication(AppBindData data) { 3122 mBoundApplication = data; 3123 mConfiguration = new Configuration(data.config); : 3149 data.info = getPackageInfoNoCheck(data.appInfo); : 3255 mInstrumentation = new Instrumentation(); : 3258 // If the app is being launched for full backup or restore, bring it up in 3259 // a restricted environment with the base application class. 3260 Application app = data.info.makeApplication(data.restrictedBackupMode, null); 3261 mInitialApplication = app; 3262 3263 List<ProviderInfo> providers = data.providers; 3264 if (providers != null) { 3265 installContentProviders(app, providers); 3266 // For process that contain content providers, we want to 3267 // ensure that the JIT is enabled "at some point". 3268 mH.sendEmptyMessageDelayed(H.ENABLE_JIT, 10*1000); 3269 } 3270 3271 try { 3272 mInstrumentation.callApplicationOnCreate(app); 3273 } catch (Exception e) { 3274 if (!mInstrumentation.onException(app, e)) { 3275 throw new RuntimeException( 3276 "Unable to create application " + app.getClass().getName() 3277 + ": " + e.toString(), e); 3278 } 3279 } 3280 }
frameworks/base/core/java/android/app/LoadedApk.java
62 /** 63 * Local state maintained about a currently loaded .apk. 65 */ 66 final class LoadedApk { : 68 private final ActivityThread mActivityThread; 69 private final ApplicationInfo mApplicationInfo; : 82 private Application mApplication; : 100 public LoadedApk(ActivityThread activityThread, ApplicationInfo aInfo, 101 ActivityThread mainThread, ClassLoader baseLoader, 102 boolean securityViolation, boolean includeCode) { 103 mActivityThread = activityThread; 104 mApplicationInfo = aInfo; 105 mPackageName = aInfo.packageName; : 444 public Application makeApplication(boolean forceDefaultAppClass, 445 Instrumentation instrumentation) { 446 if (mApplication != null) { 447 return mApplication; 448 } 449 450 Application app = null; 451 452 String appClass = mApplicationInfo.className; 453 if (forceDefaultAppClass || (appClass == null)) { 454 appClass = "android.app.Application"; 455 } 456 457 try { 458 java.lang.ClassLoader cl = getClassLoader(); 459 ContextImpl appContext = new ContextImpl(); 460 appContext.init(this, null, mActivityThread); 461 app = mActivityThread.mInstrumentation.newApplication( 462 cl, appClass, appContext); 463 appContext.setOuterContext(app); 464 } catch (Exception e) { 465 if (!mActivityThread.mInstrumentation.onException(app, e)) { 466 throw new RuntimeException( 467 "Unable to instantiate application " + appClass 468 + ": " + e.toString(), e); 469 } 470 } 471 mActivityThread.mAllApplications.add(app); 472 mApplication = app; :
frameworks/base/core/java/android/app/Instrumentation.java
928 /** 929 * Perform instantiation of the process's {@link Application} object. The 930 * default implementation provides the normal system behavior. 931 * 932 * @param cl The ClassLoader with which to instantiate the object. 933 * @param className The name of the class implementing the Application 934 * object. 935 * @param context The context to initialize the application with 936 * 937 * @return The newly instantiated Application object. 938 */ 939 public Application newApplication(ClassLoader cl, String className, Context context) 940 throws InstantiationException, IllegalAccessException, 941 ClassNotFoundException { 942 return newApplication(cl.loadClass(className), context); 943 } 944 945 /** 946 * Perform instantiation of the process's {@link Application} object. The 947 * default implementation provides the normal system behavior. 948 * 949 * @param clazz The class used to create an Application object from. 950 * @param context The context to initialize the application with 951 * 952 * @return The newly instantiated Application object. 953 */ 954 static public Application newApplication(Class clazz, Context context) 955 throws InstantiationException, IllegalAccessException, 956 ClassNotFoundException { 957 Application app = (Application)clazz.newInstance(); (→new クラス();) 958 app.attach(context); 959 return app; 960 }
962 /** 963 * Perform calling of the application's {@link Application#onCreate} 964 * method. The default implementation simply calls through to that method. 965 * 966 * @param app The application being created. 967 */ 968 public void callApplicationOnCreate(Application app) { 969 app.onCreate(); →対象 Activity の onCreate() を実行 970 }
(tanabe)