2011年09月29日

Android アプリケーションが起動するまでの流れ

はてなブックマークに登録

プログラム開発のために Android 上でアプリが起動するまでの過程を調べてみました。備忘をかねて、ソースコードをひと通り追跡した記録をここに控えます。

まとめ

※クリックすると大きな図が開きます

  • Zygote(ザイゴート)プロセスは、Android システムブート時に起動し DalvikVM 本体と Android プログラムの実行に必要なダイナミックリンクライブラリと Java のクラスライブラリをロードした状態で待機する常駐プロセスである
  • Zygote プロセスの目的は、同プロセスを fork することによりプログラム実行用のプロセス環境を素早く効率的にシステムへ提供することにある
  • UNIX ドメインソケット /dev/socket/zygote が Zygote プロセスへのインターフェイスであり、同ソケットにプロセス生成要求を送出すると Zygote はプロセス fork を実行する
  • system_server プロセスは同じくシステムブート時に起動するシステムプロセスである。Activity Manager をはじめ数多くの Android サービスはこの単一プロセス内で稼動する
  • ユーザが Android アプリ起動の操作を行うと Activity Manager 経由で Zygote にプロセス生成要求が送出される。ここで fork されるプロセスがアプリ用のプロセスとなる。つまり、すべての Android アプリケーションプロセスは Zygote の子プロセスである
  • アプリケーションプロセスの uid, gid は、当該アプリのインストール時にシステムが割り当てたものを Activity Manager が Zygote へのプロセス生成要求メッセージ内で指定し、Zygote がそれを設定するしくみ
  • Activity Manager 経由で Zygote から fork された アプリ用新規プロセスは、初期処理の段階で Activity Manager とのプロセス間通信を通じて起動対象アプリの情報を取得し、それをもとに所定のアプリをロード〜実行する。また、起動後のアプリケーションプロセスはライフサイクル管理を含め Activity Manager を中心とする文脈の中で一元管理される
※プロセスの親子関係に注意
$ 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.cppmain()
    - frameworks/base/core/java/com/android/internal/os/ZygoteInit.javamain()1. Launcher のアプリをタップ〜Activity Manager へ要求を投げるまで
    - packages/apps/Launcher2/src/com/android/launcher2/Launcher.javaonClick()startActivitySafely()
    - frameworks/base/core/java/android/app/Activity.javastartActivity()startActivityForResult()
    - frameworks/base/core/java/android/app/Instrumentation.javaexecStartActivity()
    - frameworks/base/core/java/android/app/ActivityManagerNative.javagetDefault()2. Activity Manager が Zygote へプロセス生成要求を投げるまで
    - frameworks/base/services/java/com/android/server/am/ActivityManagerService.javastartActivity()
    - frameworks/base/services/java/com/android/server/am/ActivityStack.javastartActivityMayWait()startActivityLocked()startActivityUncheckedLocked()startActivityLocked()resumeTopActivityLocked()startSpecificActivityLocked()
    - frameworks/base/services/java/com/android/server/am/ActivityManagerService.javastartProcessLocked()startProcessLocked()
    - frameworks/base/core/java/android/os/Process.javastart()startViaZygote()zygoteSendArgsAndGetResult()3. 要求を受け取った Zygote がプロセスを fork するまで
    - frameworks/base/core/java/com/android/internal/os/ZygoteInit.javarunSelectLoopMode()acceptCommandPeer()
    - frameworks/base/core/java/com/android/internal/os/ZygoteConnectionjavaZygoteConnection()runOnce()applyUidSecurityPolicy()4. fork されたプロセスが Activity Manager へ対象アプリ情報を照会するまで
    - frameworks/base/core/java/com/android/internal/os/ZygoteConnection.javahandleChildProc()
    - frameworks/base/core/java/com/android/internal/os/RuntimeInit.javazygoteInit()applicationInit()invokeStaticMain()
    - frameworks/base/core/java/com/android/internal/os/ZygoteInit.javamain()
    - frameworks/base/core/java/android/app/ActivityThread.javamain()attach()5. Activity Manager が新規プロセスに起動対象アプリ情報を渡すまで
    - frameworks/base/services/java/com/android/server/am/ActivityManagerService.javaattachApplication()attachApplicationLocked()6. 新プロセスが Activity Manager からの情報をもとにアプリを起動するまで
    - frameworks/base/core/java/android/app/ActivityThread.javabindApplication()queueOrSendMessage()handleMessage()handleBindApplication()
    - frameworks/base/core/java/android/app/LoadedApk.javamakeApplication()
    - frameworks/base/core/java/android/app/Instrumentation.javanewApplication()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&lg;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)
klab_gijutsu2 at 14:09│Comments(0)TrackBack(1)Android | win

トラックバックURL

この記事へのトラックバック

1. Androidの下回りのすごい資料  [ 電脳羊(Android Dream) ]   2011年09月29日 23:13
Android アプリケーションが起動するまでの流れ というすごい資料が公開された。

この記事にコメントする

名前:
URL:
  情報を記憶: 評価: 顔   
 
 
 
Blog内検索
このブログについて
DSASとは、KLab が構築し運用しているコンテンツサービス用のLinuxベースのインフラです。現在5ヶ所のデータセンタにて構築し、運用していますが、我々はDSASをより使いやすく、より安全に、そしてより省力で運用できることを目指して、日々改良に勤しんでいます。
このブログでは、そんな DSAS で使っている技術の紹介や、実験してみた結果の報告、トラブルに巻き込まれた時の経験談など、広く深く、色々な話題を織りまぜて紹介していきたいと思います。
最新コメント
最新トラックバック
Archives