Android App启动(上文)

ps:Android 27
本文从桌面图标点击开始,到ActivityThread#main结束

桌面Activity

  • android.app.LauncherActivity
    这是一个ListActivity,主要负责呈现手机主屏幕的桌面图标。
    // ListView的Item点击事件
    @Override 
    protected void onListItemClick(ListView l, View v, int position, long id) {
        Intent intent = intentForPosition(position);
        startActivity(intent);
    }
  • 调用Activity#startActivity(Intent intent)
  • 调用Activity#startActivity(Intent intent, Bundle options)
  • 调用Activity#startActivityForResult(Intent intent, int requestCode,Bundle options)
    public void startActivityForResult(@RequiresPermission Intent intent, int requestCode,@Nullable Bundle options) {
        // 这步其实没看懂,等看懂了再回来补充吧
        // 但最终都是会走到mInstrumentation#execStartActivity
        if (mParent == null) {
            options = transferSpringboardActivityOptions(options);
            Instrumentation.ActivityResult ar =
                mInstrumentation.execStartActivity(
                    this, mMainThread.getApplicationThread(), mToken, this,
                    intent, requestCode, options);
            if (ar != null) {
                mMainThread.sendActivityResult(
                    mToken, mEmbeddedID, requestCode, ar.getResultCode(),
                    ar.getResultData());
            }
            if (requestCode >= 0) {
                mStartedActivity = true;
            }
            cancelInputsAndStartExitTransition(options);
            // TODO Consider clearing/flushing other event sources and events for child windows.
        } else {
            if (options != null) {
                mParent.startActivityFromChild(this, intent, requestCode, options);
            } else {
                // Note we want to go through this method for compatibility with
                // existing applications that may have overridden it.
                mParent.startActivityFromChild(this, intent, requestCode);
            }
        }
    }
  • 调到 Instrumentation#execStartActivity
    public ActivityResult execStartActivity() {
        // ActivityThread的重要IBinder对象,负责跨进程通信
        IApplicationThread whoThread = (IApplicationThread) contextThread;
        ....
        try {
            ....
            // 调用AMS的startActivity,whoThread = 跨进程通信Binder
            int result = ActivityManager.getService()
                .startActivity(whoThread, who.getBasePackageName(), intent,
                        intent.resolveTypeIfNeeded(who.getContentResolver()),
                        token, target != null ? target.mEmbeddedID : null,
                        requestCode, 0, null, options);
            checkStartActivityResult(result, intent);
        } catch (RemoteException e) {
            throw new RuntimeException("Failure from system", e);
        }
        return null;
    }

那就进一步往下看吧,看看AMS的startActivity做了什么!

  • 调到 ActivityManagerService#startActivity
  • 调到 ActivityManagerService#startActivityAsUser
    在这个方法内调到了ActivityStarter内的启动逻辑
  • 调到 ActivityStarter#startActivityMayWait
    final int startActivityMayWait() {
            ....
            int res = startActivityLocked(caller, intent, ephemeralIntent, resolvedType,
                    aInfo, rInfo, voiceSession, voiceInteractor,
                    resultTo, resultWho, requestCode, callingPid,
                    callingUid, callingPackage, realCallingPid, realCallingUid, startFlags,
                    options, ignoreTargetSecurity, componentSpecified, outRecord, inTask,
                    reason);
            ....
            return res;
    }
  • 调到 ActivityStarter#startActivityLocked
    int startActivityLocked() {
        ...
        mLastStartActivityResult = startActivity(caller, intent, ephemeralIntent, resolvedType,
                aInfo, rInfo, voiceSession, voiceInteractor, resultTo, resultWho, requestCode,
                callingPid, callingUid, callingPackage, realCallingPid, realCallingUid, startFlags,
                options, ignoreTargetSecurity, componentSpecified, mLastStartActivityRecord,
                inTask);
        ...
        return mLastStartActivityResult != START_ABORTED ? mLastStartActivityResult : START_SUCCESS;
    }
  • 调到 ActivityStarter #startActivity(22 参)
  • 调到 ActivityStarter #startActivity(9 参)
    private int startActivity(9 参) {
        int result = START_CANCELED;
        try {
            result = startActivityUnchecked(r, sourceRecord, voiceSession, voiceInteractor,
                    startFlags, doResume, options, inTask, outActivity);
        } finally {
           ...
        }
        ...
        return result;
    }
  • 调到 ActivityStarter #startActivityUnchecked()
    private int startActivityUnchecked(){
        ....
        mTargetStack.startActivityLocked(mStartActivity, topFocused, newTask, mKeepCurTransition,
                mOptions);
        ....
    }
  • 调到 ActivityStack#startActivityLocked()
    final void startActivityLocked() {
            ....
            // 这种情况下,先不要启动Window
            if (r.mLaunchTaskBehind) {
                // Don't do a starting window for mLaunchTaskBehind. More importantly make sure we
                // tell WindowManager that r is visible even though it is at the back of the stack.
                r.setVisibility(true);
                ensureActivitiesVisibleLocked(null, 0, !PRESERVE_WINDOWS);
            } ...
    }
  • 调用 ActivityStack#ensureActivitiesVisibleLocked
final void ensureActivitiesVisibleLocked(ActivityRecord starting, int configChanges,boolean preserveWindows) {
        ..........
        // ProcessRecord 或者 ProcessRecord的IApplicationThread 空时
        if (r.app == null || r.app.thread == null) {
              if (makeVisibleAndRestartIfNeeded(starting, configChanges, isTop,resumeNextActivity, r)) {
                     ....
              }
        }
        ..........
    }
  • 调用ActivityStack#makeVisibleAndRestartIfNeeded
    private boolean makeVisibleAndRestartIfNeeded(ActivityRecord starting, int configChanges,
            boolean isTop, boolean andResume, ActivityRecord r) {
        // We need to make sure the app is running if it's the top, or it is just made visible from
        // invisible. If the app is already visible, it must have died while it was visible. In this
        // case, we'll show the dead window but will not restart the app. Otherwise we could end up
        // thrashing.
        if (isTop || !r.visible) {
            // This activity needs to be visible, but isn't even running...
            // get it started and resume if no other stack in this stack is resumed.
            if (DEBUG_VISIBILITY) Slog.v(TAG_VISIBILITY, "Start and freeze screen for " + r);
            if (r != starting) {
                r.startFreezingScreenLocked(r.app, configChanges);
            }
            if (!r.visible || r.mLaunchTaskBehind) {
                if (DEBUG_VISIBILITY) Slog.v(TAG_VISIBILITY, "Starting and making visible: " + r);
                r.setVisible(true);
            }
            if (r != starting) {
                mStackSupervisor.startSpecificActivityLocked(r, andResume, false);
                return true;
            }
        }
        return false;
    }
  • 调到 ActivityStackSupervisor#startSpecificActivityLocked
    void startSpecificActivityLocked() {
        // 如果进程已经创建的逻辑
        ...
        // 如果没创建进程,则开始创建进程
        mService.startProcessLocked(r.processName, r.info.applicationInfo, true, 0,"activity", r.intent.getComponent(), false, false, true);
    }
  • 调到 ActivityManagerService#startProcessLocked(9 参)
  • 调到 ActivityManagerService#startProcessLocked(14 参)
  • 调到 ActivityManagerService#startProcessLocked(6 参)
    private final void startProcessLocked(6参){
      ....
      // 注意看这里,ActivityThread类路径被当做参数传递到Process,最终会被放置到args[]中,
      // 在fork进程的请求中通过socket带到Zygote进程,下面我们分析runSelectLoop() 方法时就会恍然大悟
      if (entryPoint == null) entryPoint = "android.app.ActivityThread";
      if (hostingType.equals("webview_service")) {
          startResult = startWebView(entryPoint,
            app.processName, uid, uid, gids, debugFlags, mountExternal,
            app.info.targetSdkVersion, seInfo, requiredAbi, instructionSet,
            app.info.dataDir, null, entryPointArgs);
      } else {
          startResult = Process.start(entryPoint,
            app.processName, uid, uid, gids, debugFlags, mountExternal,
            app.info.targetSdkVersion, seInfo, requiredAbi, instructionSet,
            app.info.dataDir, invokeWith, entryPointArgs);
      }
      .....
    }
  • 调用Process#start
  • 调用ZygoteProcess#start
  • 调用ZygoteProcess#startViaZygote
  • 调用ZygoteProcess.zygoteSendArgsAndGetResult [static method]
    这里走的是socket通信,具体原因我还不太懂,等后续再补充吧。
       @GuardedBy("mLock")
    private static Process.ProcessStartResult zygoteSendArgsAndGetResult() {
        try {
            ...
            // socket 通信
            final BufferedWriter writer = zygoteState.writer;
            final DataInputStream inputStream = zygoteState.inputStream;

            writer.write(Integer.toString(args.size()));
            writer.newLine();

            for (int i = 0; i < sz; i++) {
                String arg = args.get(i);
                writer.write(arg);
                writer.newLine();
            }

            writer.flush();

            // Should there be a timeout on this?
            Process.ProcessStartResult result = new Process.ProcessStartResult();

            // Always read the entire result from the input stream to avoid leaving
            // bytes in the stream for future process starts to accidentally stumble
            // upon.
            result.pid = inputStream.readInt();
            result.usingWrapper = inputStream.readBoolean();

            if (result.pid < 0) {
                throw new ZygoteStartFailedEx("fork() failed");
            }
            return result;
        } catch (IOException ex) {
            zygoteState.close();
            throw new ZygoteStartFailedEx(ex);
        }
    }

至此,Zygote进程已经fork出一个全新的进程
在socket通信的过程中,ActivityThread.main 的启动作为一个参数被传递给Zygote进程,fork结束后,会默认调用ActivityThread#main (分析runSelectLoop的时候细看)(这是Android 27内的处理逻辑,其他版本有些差异,但整体流程大同小异)

顺便看看ActivityThread的启动
上面我们提到SystemServer进程中,ZygoteProcess#zygoteSendArgsAndGetResult方法里通过Socket将启动消息发到了Zygote进程。被ZygoteServer#runSelectLoop方法注册的消息处理器获取并处理。

  • ZygoteServer#runSelectLoop
  Runnable runSelectLoop(String abiList) {
        ...
        // 其他的就不看了
        while (true) {
            final Runnable command = connection.processOneCommand(this);
            return command;
        }
    }
  • ZygoteConnection.processOneCommand
  Runnable processOneCommand(ZygoteServer zygoteServer) {
        // 创建进程
        pid = Zygote.forkAndSpecialize(parsedArgs.uid, parsedArgs.gid, parsedArgs.gids,
                parsedArgs.debugFlags, rlimits, parsedArgs.mountExternal, parsedArgs.seInfo,
                parsedArgs.niceName, fdsToClose, fdsToIgnore, parsedArgs.instructionSet,
                parsedArgs.appDataDir);
        if (pid == 0) { 
             return handleChildProc(parsedArgs, descriptors, childPipeFd);
        } else {
             return null;
        }
    }
  • ZygoteConnection.handleChildProc
private Runnable handleChildProc(Arguments parsedArgs, FileDescriptor[] descriptors,FileDescriptor pipeFd){
    // 看到这里就熟悉了吧,返回一个ActivityThread的启动器
    return ZygoteInit.zygoteInit(parsedArgs.targetSdkVersion, parsedArgs.remainingArgs, null /*classLoader */);
 }
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,293评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,604评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,958评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,729评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,719评论 5 366
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,630评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,000评论 3 397
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,665评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,909评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,646评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,726评论 1 330
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,400评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,986评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,959评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,197评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 44,996评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,481评论 2 342

推荐阅读更多精彩内容