精华内容
下载资源
问答
  • Android app启动页广告

    热门讨论 2016-12-15 10:26:22
    Android app启动也得广告,时间倒计时,支持跳过。详情见博客:http://blog.csdn.net/u010918416/article/details/52924930
  • 仿写了几种App启动欢迎页面 很实用 很漂亮 包含了常见的几种启动画面
  • Android 一个app启动另一个app

    热门讨论 2014-09-12 16:08:11
    一个app启动另一个app,这个玩法挺火的嘛,有没有试过更新QQ到5.1版本,QQ的健康里面就可以添加其他app,实现从QQ跳转到其他app应用,这里模拟写了一个demo
  • Android App启动流程详解

    万次阅读 多人点赞 2019-06-26 15:26:19
    前言:在之前的文章中已经写了apk的打包流程、安装流程,今天就是梳理一下apk系列的最后的流程--app启动流程。经过今天的梳理以后咱们就可以对apk包是怎么编译生成的、apk是怎么被安装到安卓手机的、用户点击了桌面...

    前言:在之前的文章中已经写了apk的打包流程、安装流程,今天就是梳理一下apk系列的最后的流程--app启动流程。经过今天的梳理以后咱们就可以对apk包是怎么编译生成的、apk是怎么被安装到安卓手机的、用户点击了桌面icon以后app是怎么启动起来的 整个流程有清晰的认知和了解了。

    下面先附上前面文章的传送门:

    apk打包流程详解

    apk安装流程详解

    在开始分析app启动流程之前,我们先回想下平时是怎么启动一个App的:Android系统桌面->点击应用图标->启动App。

    从这个过程来看,只要弄明白下面两个问题就可以解决我们“App如何被启动”的疑问。

     

    在最开始先将apk启动涉及的“三个进程”,“六个大类”进行介绍一下:

    • Android系统桌面是什么?
    • 点击应用图标后Android系统执行了什么操作?

    三个进程:

    Launcher进程:整个App启动流程的起点,负责接收用户点击屏幕事件,它其实就是一个Activity,里面实现了点击事件,长按事件,触摸等事件,可以这么理解,把Launcher想象成一个总的Activity,屏幕上各种App的Icon就是这个Activity的button,当点击Icon时,会从Launcher跳转到其他页面。

    SystemServer进程:这个进程在整个的Android进程中是非常重要的一个,地位和Zygote等同,它是属于Application Framework层的,Android中的所有服务,例如AMS, WindowsManager, PackageManagerService等等都是由这个SystemServer fork出来的。

    App进程:你要启动的App所运行的进程。

    六个大类:

    ActivityManagerService:(AMS)AMS是Android中最核心的服务之一,主要负责系统中四大组件的启动、切换、调度及应用进程的管理和调度等工作,其职责与操作系统中的进程管理和调度模块相类似,因此它在Android中非常重要,它本身也是一个Binder的实现类。

    Instrumentation:监控应用程序和系统的交互。

    ActivityThread:应用的入口类,通过调用main方法,开启消息循环队列。ActivityThread所在的线程被称为主线程。

    ApplicationThread:ApplicationThread提供Binder通讯接口,AMS则通过代理调用此App进程的本地方法。

    ActivityManagerProxy:AMS服务在当前进程的代理类,负责与AMS通信。

    ApplicationThreadProxy:ApplicationThread在AMS服务中的代理类,负责与ApplicationThread通信。

    可以说,启动的流程就是通过这六个大类在这三个进程之间不断通信的过程。

    先搞清楚Android系统桌面是什么?

    在Android系统中,Activity是视图存在的根本,那么我们可以通过命令 adb shell dumpsys activity activities 判断是哪个Activity为我们呈现桌面视图的。

    以小米为例,通过USB连上电脑后,输入命令 adb shell dumpsys activity activities 得到结果如下:

    在上图可以看到,显示桌面视图的Activity是com.miui.home包下的名为Launcher的Activity。

    下面我copy了一张Launcher的这个Activity:

    再来说说点击App图标后Android系统执行了什么操作?

    既然Launcher是Activity,那就意味着我们点击桌面的事件可以表达为:呈现Android桌面视图(View)->点击View上某个应用图标->产生点击事件->点击事件被响应->通知Android系统的某个/某些进程->Android系统执行某些操作->启动App。

    先看一下Launcher如何响应由我们产生的点击事件的:

    /**
     * Launches the intent referred by the clicked shortcut.
     *
     * @param v The view representing the clicked shortcut.
     */
    public void onClick(View v) {
        // Make sure that rogue clicks don't get through while allapps is launching, or after the
        // view has detached (it's possible for this to happen if the view is removed mid touch).
        if (v.getWindowToken() == null) {
            return;
        }
    
        if (!mWorkspace.isFinishedSwitchingState()) {
            return;
        }
    
        Object tag = v.getTag();
        if (tag instanceof ShortcutInfo) {
            // Open shortcut
            final Intent intent = ((ShortcutInfo) tag).intent;
            int[] pos = new int[2];
            v.getLocationOnScreen(pos);
            intent.setSourceBounds(new Rect(pos[0], pos[1],
                    pos[0] + v.getWidth(), pos[1] + v.getHeight()));
    
            boolean success = startActivitySafely(v, intent, tag);
    
            if (success && v instanceof BubbleTextView) {
                mWaitingForResume = (BubbleTextView) v;
                mWaitingForResume.setStayPressed(true);
            }
        } else if (tag instanceof FolderInfo) {
            if (v instanceof FolderIcon) {
                FolderIcon fi = (FolderIcon) v;
                handleFolderClick(fi);
            }
        } else if (v == mAllAppsButton) {
            if (isAllAppsVisible()) {
                showWorkspace(true);
            } else {
                onClickAllAppsButton(v);
            }
        }
    }
    
    boolean startActivitySafely(View v, Intent intent, Object tag) {
        boolean success = false;
        try {
            success = startActivity(v, intent, tag);
        } catch (ActivityNotFoundException e) {
            Toast.makeText(this, R.string.activity_not_found, Toast.LENGTH_SHORT).show();
            Log.e(TAG, "Unable to launch. tag=" + tag + " intent=" + intent, e);
        }
        return success;
    }
    

    从上面代码来看,产生点击事件后,如果产生点击事件的View的Tag是ShortcutInfo(即启动应用的快捷方式),就会取得ShortcutInfo中保存的Intent(这个Intent指向我们要启动的App),然后执行startActivitySafely(v, intent, tag)方法,而startActivitySafely方法只是对startActivity方法的简单封装。

    所以,Launcher响应我们产生的点击事件后,实际上就是启动一个新的Activity。

    我们现在回想下在App开发时,每个App都需要有一个“MainActivity”,这个Activity必须在AndroidManifest.xml文件中有以下配置:

    <intent-filter>    
        <action android:name="android.intent.action.MAIN" />    
        <category android:name="android.intent.category.LAUNCHER" />    
    </intent-filter> 
    

    在配置AndroidManifest.xml文件时,将Activity的Action指定为android.intent.action.MAIN,会使Activity在一个新的Task中启动(Task是一个Activity栈)。将category指定为android.intent.category.LAUNCHER,表示通过Intent启动此Activity时,只接受category为LAUNCHER的Intent。

    所以,Launcher将会通过App的快捷方式(ShortcutInfo)得到应用的Intent,并通过这个Intent启动应用的“MainActivity”,从而启动应用。

    到此我们研究的问题就从“App启动流程”变为“Activity启动流程”。

    接下来我们就进入Launcher的startActivity方法里面探索“Activity启动流程”吧:在系统中其实Launcher是通过Binder通知ActivityManagerService启动Activity的。看下面的代码:

    boolean startActivity(View v, Intent intent, Object tag) {
        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
    
        try {
            // Only launch using the new animation if the shortcut has not opted out (this is a
            // private contract between launcher and may be ignored in the future).
            boolean useLaunchAnimation = (v != null) &&
                    !intent.hasExtra(INTENT_EXTRA_IGNORE_LAUNCH_ANIMATION);
            UserHandle user = (UserHandle) intent.getParcelableExtra(ApplicationInfo.EXTRA_PROFILE);
            LauncherApps launcherApps = (LauncherApps)
                    this.getSystemService(Context.LAUNCHER_APPS_SERVICE);
            if (useLaunchAnimation) {
                ActivityOptions opts = ActivityOptions.makeScaleUpAnimation(v, 0, 0,
                        v.getMeasuredWidth(), v.getMeasuredHeight());
                if (user == null || user.equals(android.os.Process.myUserHandle())) {
                    // Could be launching some bookkeeping activity
                    startActivity(intent, opts.toBundle());
                } else {
                    launcherApps.startMainActivity(intent.getComponent(), user,
                            intent.getSourceBounds(),
                            opts.toBundle());
                }
            } else {
                if (user == null || user.equals(android.os.Process.myUserHandle())) {
                    startActivity(intent);
                } else {
                    launcherApps.startMainActivity(intent.getComponent(), user,
                            intent.getSourceBounds(), null);
                }
            }
            return true;
        } catch (SecurityException e) {
            Toast.makeText(this, R.string.activity_not_found, Toast.LENGTH_SHORT).show();
            Log.e(TAG, "Launcher does not have the permission to launch " + intent +
                    ". Make sure to create a MAIN intent-filter for the corresponding activity " +
                    "or use the exported attribute for this activity. "
                    + "tag="+ tag + " intent=" + intent, e);
        }
        return false;
    }
    

    在这个方法中,首先,将Intent的Flag设为Intent.FLAG_ACTIVITY_NEW_TASK,使得Android系统将创建一个新的Task来放置即将被打开的新Activity(应用的“MainActivity),然后获取一个布尔值以用于后续判断是否显示启动App的动画。

    再然后获取Intent中是否传输了Parcelable格式的用户句柄,并通过Context.LAUNCHER_APPS_SERVICE获取用于在多用户情境下启动App的系统服务。

    不管是否显示启动App的动画,最终都会执行startActivity(intent)或launcherApps.startMainActivity方法以启动应用的“MainActivity”。而launcherApps.startMainActivity只在用户句柄不为空且用户句柄不等于当前进程句柄时(其他用户的句柄)调用。

    那为什么用户句柄会影响Activity的启动方式呢?

    这一点和Android的多用户安全机制有关。

    假设我们有用户A和用户B在使用同一台手机,用户A是无法访问到用户B的文件或者和用户B的App通信的。所以假如我们现在是用户A,但我们想启动用户B的App,是无法直接实现的,因为用户A没有权限访问到用户B的数据,即使我们在代码中强行把user id设为用户B的user id,交给内核执行时也会抛出SecurityException。因此我们需要取得用户A的句柄(和用户A相关的数据),将我们想启动的用户B的App的Intent、用户A的句柄交给内核,让拥有权限的Android系统服务(内核态进程)去访问用户B的数据并执行相关的操作。

    假如是单用户情境,就会相对简单了。因为此时只有一个用户,而该用户始终有权限直接访问自己的数据。

    接下来继续看startActivity(intent)如何启动Activity,进入Activity类后层层深入就可以看到最终调用的是startActivityForResult方法:

    public void startActivityForResult(Intent intent, int requestCode, @Nullable Bundle options) {
        if (mParent == null) {
            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) {
                // If this start is requesting a result, we can avoid making
                // the activity visible until the result is received.  Setting
                // this code during onCreate(Bundle savedInstanceState) or onResume() will keep the
                // activity hidden during this time, to avoid flickering.
                // This can only be done when a result is requested because
                // that guarantees we will get information back when the
                // activity is finished, no matter what happens to it.
                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);
            }
        }
    }
    

    从代码上看,如果Launcher有mParent Activity,就会执行mParent.startActivityFromChild;如果没有,就会执行mInstrumentation.execStartActivity。进入mParent.startActivityFromChild方法会看到最终也是执行了mInstrumentation.execStartActivity。执行完成后,会取得一个ActivityResult对象,用于给调用者Activity传递一些数据,最后在Activity切换时显示Transition动画。

    这里有一点需要指出的是:这里的ParentActivity指的是类似TabActivity、ActivityGroup关系的嵌套Activity。之所以要强调parent和child,是要避免混乱的Activity嵌套关系。

    下面我们进入Instrumentation类看看execStartActivity方法:

    public ActivityResult execStartActivity(
            Context who, IBinder contextThread, IBinder token, Activity target,
            Intent intent, int requestCode, Bundle options) {
        IApplicationThread whoThread = (IApplicationThread) contextThread;
        Uri referrer = target != null ? target.onProvideReferrer() : null;
        if (referrer != null) {
            intent.putExtra(Intent.EXTRA_REFERRER, referrer);
        }
        if (mActivityMonitors != null) {
            synchronized (mSync) {
                final int N = mActivityMonitors.size();
                for (int i=0; i<N; i++) {
                    final ActivityMonitor am = mActivityMonitors.get(i);
                    if (am.match(who, null, intent)) {
                        am.mHits++;
                        if (am.isBlocking()) {
                            return requestCode >= 0 ? am.getResult() : null;
                        }
                        break;
                    }
                }
            }
        }
        try {
            intent.migrateExtraStreamToClipData();
            intent.prepareToLeaveProcess();
            int result = ActivityManagerNative.getDefault()
                .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;
    }
    

    首先,我们通过参数IBinder contextThread取得一个IApplicationThread类型的对象whoThread,而contextThread是由mMainThread.getApplicationThread()取得的ApplicationThread对象,此时mMainThread指的就是Launcher应用的主线程,所以whoThread指代的自然是Launcher的ApplicationThread。

    因为Activity的onProvideReferrer()方法默认返回null,除非该方法被重写,而我们使用的Launcher并没有重写该方法,所以不用管referrer。

    然后判断是否有ActivityMonitor,如果有,则即将要打开的Activity是否和ActivityMonitor中保存的IntentFilter匹配,如果匹配则增加ActivityMonitor的计数。大致是用于监控符合匹配规则的Activity的数量的。

    最后调用ActivityManagerNative.getDefault().startActivity(whoThread, who.getBasePackageName(), intent, intent.resolveTypeIfNeeded(who.getContentResolver()), token, target != null ? target.mEmbeddedID : null, requestCode, 0, null, options);启动Activity,并检查启动是否成功。

    换句话说,最终负责启动Activity的是ActivityManager,前面得到的ApplicationThread也是在这里使用的。

    那么ActivityManager、ApplicationThread、ActivityThread都是什么呢?接下来进行解答。

    友情提示:在启动Activity的时候ActivityManagerService会通过Binder将Launcher切换到pause状态。

    接着往下看,首先,调用ActivityManagerNative.getDefault()方法实际调用的是asInterface(IBinder obj)方法,也就意味着我们使用的其实是ActivityManagerProxy,而ActivityManagerProxy则是ActivityManagerService的代理,详见下面的代码:

    static public IActivityManager getDefault() {
            return gDefault.get();
        }
    
    private static final Singleton<IActivityManager> gDefault = new Singleton<IActivityManager>() {
        protected IActivityManager create() {
            IBinder b = ServiceManager.getService("activity");
            if (false) {
                Log.v("ActivityManager", "default service binder = " + b);
            }
            IActivityManager am = asInterface(b);
            if (false) {
                Log.v("ActivityManager", "default service = " + am);
            }
            return am;
        }
    };
    
    static public IActivityManager asInterface(IBinder obj) {
        if (obj == null) {
            return null;
        }
        IActivityManager in =
            (IActivityManager)obj.queryLocalInterface(descriptor);
        if (in != null) {
            return in;
        }
    
        return new ActivityManagerProxy(obj);
    }
    

    那么继续进入ActivityManagerProxy看:

    class ActivityManagerProxy implements IActivityManager
    {
        public ActivityManagerProxy(IBinder remote)
        {
            mRemote = remote;
        }
    
        public IBinder asBinder()
        {
            return mRemote;
        }
    
        public int startActivity(IApplicationThread caller, String callingPackage, Intent intent,
                String resolvedType, IBinder resultTo, String resultWho, int requestCode,
                int startFlags, ProfilerInfo profilerInfo, Bundle options) throws RemoteException {
            // 创建两个Parcel对象,data用于传输启动Activity需要的数据,reply用于获取
            // 启动Activity操作执行后系统返回的响应
            Parcel data = Parcel.obtain();
            Parcel reply = Parcel.obtain();
            data.writeInterfaceToken(IActivityManager.descriptor);
            // caller 就是Launcher提供的ApplicationThread(也就是前面提到的whoThread)
            data.writeStrongBinder(caller != null ? caller.asBinder() : null);
            // 记录启动新Activity的应用的包名,也就是Launcher的包名
            data.writeString(callingPackage);
            intent.writeToParcel(data, 0);
            data.writeString(resolvedType);
            // 将resultTo这个IBinder对象写入data,实际写入的就是前面的参数——IBinder token
            // 而这个token是什么,我们暂时不管,后面会给出解释
            data.writeStrongBinder(resultTo);
            data.writeString(resultWho);
            data.writeInt(requestCode);
            data.writeInt(startFlags);
            if (profilerInfo != null) {
                data.writeInt(1);
                profilerInfo.writeToParcel(data, Parcelable.PARCELABLE_WRITE_RETURN_VALUE);
            } else {
                data.writeInt(0);
            }
            if (options != null) {
                data.writeInt(1);
                options.writeToParcel(data, 0);
            } else {
                data.writeInt(0);
            }
            mRemote.transact(START_ACTIVITY_TRANSACTION, data, reply, 0);
            reply.readException();
            int result = reply.readInt();
            reply.recycle();
            data.recycle();
            return result;
        }
    ……省略余下代码……
    }
    

    将数据都写入后,就通过mRemote.transact(START_ACTIVITY_TRANSACTION, data, reply, 0)传输数据并得到响应(写入reply)。

    前面已经提到了,ActivityManagerProxy是ActivityManagerService的代理,那么调用mRemote.transact(START_ACTIVITY_TRANSACTION, data, reply, 0)实际上就是通过Binder建立Launcher所在的进程与system_server进程(Android Framework层的服务几乎都由system_server进程管理,因此ActivityManagerService运行在system_server进程中)的通信,并把我们写入data的数据通过Binder传递给ActivityManagerService。

    ActivityManagerService得到我们用Parcelable封装的data后就会调用startActivity方法为Launcher启动Activity:

    @Override
    public final int startActivity(IApplicationThread caller, String callingPackage,
            Intent intent, String resolvedType, IBinder resultTo, String resultWho, int requestCode,
            int startFlags, ProfilerInfo profilerInfo, Bundle options) {
        return startActivityAsUser(caller, callingPackage, intent, resolvedType, resultTo,
            resultWho, requestCode, startFlags, profilerInfo, options,
            UserHandle.getCallingUserId());
    }
    
    @Override
    public final int startActivityAsUser(IApplicationThread caller, String callingPackage,
            Intent intent, String resolvedType, IBinder resultTo, String resultWho, int requestCode,
            int startFlags, ProfilerInfo profilerInfo, Bundle options, int userId) {
        enforceNotIsolatedCaller("startActivity");
        userId = handleIncomingUser(Binder.getCallingPid(), Binder.getCallingUid(), userId,
                false, ALLOW_FULL_ONLY, "startActivity", null);
        // TODO: Switch to user app stacks here.
        return mStackSupervisor.startActivityMayWait(caller, -1, callingPackage, intent,
                resolvedType, null, null, resultTo, resultWho, requestCode, startFlags,
                profilerInfo, null, null, options, false, userId, null, null);
    }
    
    void enforceNotIsolatedCaller(String caller) {
        if (UserHandle.isIsolated(Binder.getCallingUid())) {
            throw new SecurityException("Isolated process not allowed to call " + caller);
        }
    }
    

    enforceNotIsolatedCaller("startActivity");作安全性检查,判断当前用户是否允许启动Activity,然后对之前传入的userId进行转换和安全性检查。最后调用mStackSupervisor.startActivityMayWait。这里的mStackSupervisor是ActivityStackSupervisor对象,前面提到过,Task是以堆栈形式组织Activity的集合,而Task又由ActivityStack管理,ActivityStackSupervisor则是管理ActivityStack的类。

    源码太多,下面截取部分关键代码来说一下:

    首先,通过下面代码段调用PackageManagerService解析Intent(我们想要打开的App的用于启动MainActivity的Intent),将解析的结果保存到ActivityInfo类型的对象里:

    // Collect information about the target of the Intent.
            ActivityInfo aInfo =
                    resolveActivity(intent, resolvedType, startFlags, profilerInfo, userId);
    
    // Method - resolveActivity
        ActivityInfo resolveActivity(Intent intent, String resolvedType, int startFlags,
                ProfilerInfo profilerInfo, int userId) {
            // Collect information about the target of the Intent.
            ActivityInfo aInfo;
            try {
                ResolveInfo rInfo =
                    AppGlobals.getPackageManager().resolveIntent(
                            intent, resolvedType,
                            PackageManager.MATCH_DEFAULT_ONLY
                                        | ActivityManagerService.STOCK_PM_FLAGS, userId);
                aInfo = rInfo != null ? rInfo.activityInfo : null;
            } catch (RemoteException e) {
                aInfo = null;
            }
    
    ……省略,大致是做一些安全性检查和相关信息的设置……
            return aInfo;
        }
    

    然后互斥锁锁住ActivityManagerService的实例mService,如果解析的ActivityInfo不为空,且ApplicationInfo有ApplicationInfo.PRIVATE_FLAG_CANT_SAVE_STATE标记,意味着调用者App是属于heavy-weight process,如果现在有另一个heavy-weight process正在运行,则需要进行一些额外的处理,然后进入到startActivityLocked方法。

    这里通过注释我们可以发现,若App有ApplicationInfo.PRIVATE_FLAG_CANT_SAVE_STATE标记,App就可视为heavy-weight process,该标记可以在AndroidManifest.xml中设置,它是用于声明App是否享受系统提供的Activity状态保存/恢复功能的。但是似乎没有App能成为heavy-weight process,因为PackageParser的parseApplication方法并不会解析该标签。

    之后在startActivityLocked方法中,得到Launcher(Activity)的ActivityRecord(Activity相关的信息),并创建我们要启动的Activity的ActivityRecord,最终执行startActivityUncheckedLocked继续启动Activity:

    ActivityRecord sourceRecord = null;
            ActivityRecord resultRecord = null;
            if (resultTo != null) {
                sourceRecord = isInAnyStackLocked(resultTo);
                if (DEBUG_RESULTS) Slog.v(TAG_RESULTS,
                        "Will send result to " + resultTo + " " + sourceRecord);
                if (sourceRecord != null) {
                    if (requestCode >= 0 && !sourceRecord.finishing) {
                        resultRecord = sourceRecord;
                    }
                }
            }
    
    …………
    
    ActivityRecord r = new ActivityRecord(mService, callerApp, callingUid, callingPackage,
                    intent, resolvedType, aInfo, mService.mConfiguration, resultRecord, resultWho,
                    requestCode, componentSpecified, voiceSession != null, this, container, options);
    
    ……
    
    err = startActivityUncheckedLocked(r, sourceRecord, voiceSession, voiceInteractor,
                    startFlags, true, options, inTask);
    

    进入startActivityUncheckedLocked方法,完成一些简单的初始化后,向下执行到这段代码:如果Intent里有Intent.FLAG_ACTIVITY_NEW_DOCUMENT标记(在AndroidManifest.xml中声明),且即将要打开的Activity的启动模式又被声明为SingleInstance或SingleTask,那么Intent中携带的标记和AndroidManifest中声明的标记出现冲突,而AndroidManifest的优先级是高于Intent的,因此将launchFlags的对应位置为0。

    然后是对launchFlags一系列的置位,目的是设置启动模式。

    if ((launchFlags & Intent.FLAG_ACTIVITY_NEW_DOCUMENT) != 0 &&
                (launchSingleInstance || launchSingleTask)) {
        // We have a conflict between the Intent and the Activity manifest, manifest wins.
        Slog.i(TAG, "Ignoring FLAG_ACTIVITY_NEW_DOCUMENT, launchMode is " +
                "\"singleInstance\" or \"singleTask\"");
        launchFlags &=
                ~(Intent.FLAG_ACTIVITY_NEW_DOCUMENT | Intent.FLAG_ACTIVITY_MULTIPLE_TASK);
        } else {
            switch (r.info.documentLaunchMode) {
                case ActivityInfo.DOCUMENT_LAUNCH_NONE:
                    break;
                case ActivityInfo.DOCUMENT_LAUNCH_INTO_EXISTING:
                    launchFlags |= Intent.FLAG_ACTIVITY_NEW_DOCUMENT;
                    break;
                case ActivityInfo.DOCUMENT_LAUNCH_ALWAYS:
                    launchFlags |= Intent.FLAG_ACTIVITY_NEW_DOCUMENT;
                    break;
                case ActivityInfo.DOCUMENT_LAUNCH_NEVER:
                    launchFlags &= ~Intent.FLAG_ACTIVITY_MULTIPLE_TASK;
                    break;
            }
        }
    }
    ……
    
    if ((launchFlags & Intent.FLAG_ACTIVITY_NEW_DOCUMENT) != 0 && r.resultTo == null) {
        launchFlags |= Intent.FLAG_ACTIVITY_NEW_TASK;
    }
    
    // If we are actually going to launch in to a new task, there are some cases where
    // we further want to do multiple task.
    if ((launchFlags & Intent.FLAG_ACTIVITY_NEW_TASK) != 0) {
        if (launchTaskBehind
                || r.info.documentLaunchMode == ActivityInfo.DOCUMENT_LAUNCH_ALWAYS) {
            launchFlags |= Intent.FLAG_ACTIVITY_MULTIPLE_TASK;
        }
    }
    
    ……
    
    if (inTask == null) {
        if (sourceRecord == null) {
            // This activity is not being started from another...  in this
            // case we -always- start a new task.
            if ((launchFlags & Intent.FLAG_ACTIVITY_NEW_TASK) == 0 && inTask == null) {
                Slog.w(TAG, "startActivity called from non-Activity context; forcing " +
                        "Intent.FLAG_ACTIVITY_NEW_TASK for: " + intent);
                launchFlags |= Intent.FLAG_ACTIVITY_NEW_TASK;
            }
        } else if (sourceRecord.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE) {
            // The original activity who is starting us is running as a single
            // instance...  this new activity it is starting must go on its
            // own task.
            launchFlags |= Intent.FLAG_ACTIVITY_NEW_TASK;
        } else if (launchSingleInstance || launchSingleTask) {
            // The activity being started is a single instance...  it always
            // gets launched into its own task.
            launchFlags |= Intent.FLAG_ACTIVITY_NEW_TASK;
        }
    }
    
    ……
    
    // 因为我们是从Launcher启动目的Activity,所以sourceRecord不为null,值为Launcher的ActivityRecord
    if (sourceRecord != null) {
        if (sourceRecord.finishing) {
            // 如果sourceRecord表示的Activity正在结束/被销毁,那么我们不能把该Activity看作启动目的
            // Activity的源Activity,因为和源Activity关联的Task现在可能是空的(没有Activity)或者
            // 也在结束/被销毁的过程中,所以我们不能盲目地把目的Activity放到该Task中。取而代之的是,
            // 我们会为它找到一个可用的Task,但我们要先保存源Activity的Task的信息,使得我们在创建新
            // 的可用的Task时能用到里面的一些信息。
            if ((launchFlags & Intent.FLAG_ACTIVITY_NEW_TASK) == 0) {
                Slog.w(TAG, "startActivity called from finishing " + sourceRecord
                        + "; forcing " + "Intent.FLAG_ACTIVITY_NEW_TASK for: " + intent);
                launchFlags |= Intent.FLAG_ACTIVITY_NEW_TASK;
                newTaskInfo = sourceRecord.info;
                newTaskIntent = sourceRecord.task.intent;
            }
            sourceRecord = null;
            sourceStack = null;
        } else {
            sourceStack = sourceRecord.task.stack;
        }
    } else {
        sourceStack = null;
    }
    
    ……
    
    // 为目的Activity创建新的Task
    if (r.resultTo == null && inTask == null && !addingToTask
            && (launchFlags & Intent.FLAG_ACTIVITY_NEW_TASK) != 0) {
        newTask = true;
        targetStack = computeStackFocus(r, newTask);
        targetStack.moveToFront("startingNewTask");
    
        if (reuseTask == null) {
            r.setTask(targetStack.createTaskRecord(getNextTaskId(),
                    newTaskInfo != null ? newTaskInfo : r.info,
                    newTaskIntent != null ? newTaskIntent : intent,
                    voiceSession, voiceInteractor, !launchTaskBehind /* toTop */),
                    taskToAffiliate);
            if (DEBUG_TASKS) Slog.v(TAG_TASKS,
                    "Starting new activity " + r + " in new task " + r.task);
        } else {
            r.setTask(reuseTask, taskToAffiliate);
        }
        if (isLockTaskModeViolation(r.task)) {
            Slog.e(TAG, "Attempted Lock Task Mode violation r=" + r);
            return ActivityManager.START_RETURN_LOCK_TASK_MODE_VIOLATION;
        }
        if (!movedHome) {
            if ((launchFlags &
                    (FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_TASK_ON_HOME))
                    == (FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_TASK_ON_HOME)) {
                // Caller wants to appear on home activity, so before starting
                // their own activity we will bring home to the front.
                r.task.setTaskToReturnTo(HOME_ACTIVITY_TYPE);
            }
        }
    }
    

    完成上面一系列的处理后,调用ActivityStack的startActivityLocked方法继续执行启动Activity需要的操作,targetStack是通过这行代码targetStack = computeStackFocus(r, newTask)为用户新建的ActivityStack:

    mService.grantUriPermissionFromIntentLocked(callingUid, r.packageName,
            intent, r.getUriPermissionsLocked(), r.userId);
    
    if (sourceRecord != null && sourceRecord.isRecentsActivity()) {
        r.task.setTaskToReturnTo(RECENTS_ACTIVITY_TYPE);
    }
    if (newTask) {
        EventLog.writeEvent(EventLogTags.AM_CREATE_TASK, r.userId, r.task.taskId);
    }
    ActivityStack.logStartActivity(EventLogTags.AM_CREATE_ACTIVITY, r, r.task);
    targetStack.mLastPausedActivity = null;
    targetStack.startActivityLocked(r, newTask, doResume, keepCurTransition, options);
    if (!launchTaskBehind) {
        // Don't set focus on an activity that's going to the back.
        mService.setFocusedActivityLocked(r, "startedActivity");
    }
    return ActivityManager.START_SUCCESS;
    

    进入到ActivityStack的startActivityLocked方法,首先为目的Activity创建ProcessRecord,然后用WindowManager进行一些切换窗口的操作,最后调用mStackSupervisor.resumeTopActivitiesLocked(this, r, options):

    if (!isHomeStack() || numActivities() > 0) {
        // We want to show the starting preview window if we are
        // switching to a new task, or the next activity's process is
        // not currently running.
        boolean showStartingIcon = newTask;
        ProcessRecord proc = r.app;
        if (proc == null) {
            proc = mService.mProcessNames.get(r.processName, r.info.applicationInfo.uid);
        }
        if (proc == null || proc.thread == null) {
            showStartingIcon = true;
        }
        ……调用WindowManager切换窗口……
    }
    
    ……
    
    if (doResume) {
        mStackSupervisor.resumeTopActivitiesLocked(this, r, options);
    }
    

    进入到resumeTopActivitiesLocked方法,调用resumeTopActivityLocked方法将所有ActivityStack(多个显示设备,每个设备对应一个ActivityStack)栈顶的Activity切换到resume状态(生命周期的onResume),而resumeTopActivityLocked方法先避免递归调用,然后调用ActivityStack的resumeTopActivityInnerLocked方法:

    boolean resumeTopActivitiesLocked(ActivityStack targetStack, ActivityRecord target,
            Bundle targetOptions) {
        if (targetStack == null) {
            targetStack = mFocusedStack;
        }
        // Do targetStack first.
        boolean result = false;
        if (isFrontStack(targetStack)) {
            result = targetStack.resumeTopActivityLocked(target, targetOptions);
        }
    
        for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) {
            final ArrayList<ActivityStack> stacks = mActivityDisplays.valueAt(displayNdx).mStacks;
            for (int stackNdx = stacks.size() - 1; stackNdx >= 0; --stackNdx) {
                final ActivityStack stack = stacks.get(stackNdx);
                if (stack == targetStack) {
                    // Already started above.
                    continue;
                }
                if (isFrontStack(stack)) {
                    stack.resumeTopActivityLocked(null);
                }
            }
        }
        return result;
    }
    

    下面resumeTopActivityInnerLocked()这段代码主要就是做一些前期的检查,避免做多余的工作浪费时间,并且确保目标Activity处于正确的“状态”,使得我们后面能把它切换到resume状态并显示:

    private boolean resumeTopActivityInnerLocked(ActivityRecord prev, Bundle options) {
    
        // 判断ActivityManagerService是否已经启动完毕
        if (!mService.mBooting && !mService.mBooted) {
            // Not ready yet!
            return false;
        }
    
        // 获取parentActivity,如果parentActivity还未处于resume状态,则不能将stack栈顶的Activity切换为resume状态(Activity的嵌套关系不能弄乱)
        ActivityRecord parent = mActivityContainer.mParentActivity;
        if ((parent != null && parent.state != ActivityState.RESUMED) ||
                !mActivityContainer.isAttachedLocked()) {
            // Do not resume this stack if its parent is not resumed.
            // TODO: If in a loop, make sure that parent stack resumeTopActivity is called 1st.
            return false;
        }
    
        // 如果有正在初始化的Activity没有位于ActivityStack的栈顶,且正在执行window的启动和显示,
        // 则要将window相关的操作取消。因为这类Activity的窗口有可能被孤立,那么它们有可能永远也不会进入resume状态
        cancelInitializingActivities();
    
        // 取得当前ActivityStack栈顶Activity的ActivityRecord
        final ActivityRecord next = topRunningActivityLocked(null);
    
        // 记住我们怎样处理pause/resume状态切换,并确保无论何时结束处理都会重置状态
        final boolean userLeaving = mStackSupervisor.mUserLeaving;
        mStackSupervisor.mUserLeaving = false;
    
        final TaskRecord prevTask = prev != null ? prev.task : null;
        if (next == null) {
            // next为null表示当前ActivityStack没有要显示的Activity
            final String reason = "noMoreActivities";
            if (!mFullscreen) {
                // 如果当前ActivityStack不是全屏的,将焦点切换到下一个拥有Activity的可见ActivityStack中
                final ActivityStack stack = getNextVisibleStackLocked();
                if (adjustFocusToNextVisibleStackLocked(stack, reason)) {
                    return mStackSupervisor.resumeTopActivitiesLocked(stack, prev, null);
                }
            }
            // 如果ActivityStack是全屏的,却没有可以显示的Activity,那么就显示桌面(Launcher)
            ActivityOptions.abort(options);
            if (DEBUG_STATES) Slog.d(TAG_STATES,
                    "resumeTopActivityLocked: No more activities go home");
            if (DEBUG_STACK) mStackSupervisor.validateTopActivitiesLocked();
            final int returnTaskType = prevTask == null || !prevTask.isOverHomeStack() ?
                    HOME_ACTIVITY_TYPE : prevTask.getTaskToReturnTo();
            return isOnHomeDisplay() &&
                    mStackSupervisor.resumeHomeStackTask(returnTaskType, prev, reason);
        }
    
        next.delayedResume = false;
    
        // 如果当前栈顶Activity处于resume状态,且就是我们要打开的Activity,则直接结束
        if (mResumedActivity == next && next.state == ActivityState.RESUMED &&
                    mStackSupervisor.allResumedActivitiesComplete()) {
            // Make sure we have executed any pending transitions, since there
            // should be nothing left to do at this point.
            mWindowManager.executeAppTransition();
            mNoAnimActivities.clear();
            ActivityOptions.abort(options);
            if (DEBUG_STATES) Slog.d(TAG_STATES,
                    "resumeTopActivityLocked: Top activity resumed " + next);
            if (DEBUG_STACK) mStackSupervisor.validateTopActivitiesLocked();
            return false;
        }
    
        // 对prevActivity(Launcher)所在的Task进行一些判断,如果prevTask和nextTask相同,那么直接将
        // prevTask直接设为栈顶Task;如果prevTask不是当前ActivityStack栈顶的Task,那么它后面的Task
        // 都应该放到Launcher的Task后面;后面则是有关是否为桌面的判断和处理了。
        final TaskRecord nextTask = next.task;
        if (prevTask != null && prevTask.stack == this &&
                prevTask.isOverHomeStack() && prev.finishing && prev.frontOfTask) {
            if (DEBUG_STACK)  mStackSupervisor.validateTopActivitiesLocked();
            if (prevTask == nextTask) {
                prevTask.setFrontOfTask();
            } else if (prevTask != topTask()) {
                // This task is going away but it was supposed to return to the home stack.
                // Now the task above it has to return to the home task instead.
                final int taskNdx = mTaskHistory.indexOf(prevTask) + 1;
                mTaskHistory.get(taskNdx).setTaskToReturnTo(HOME_ACTIVITY_TYPE);
            } else if (!isOnHomeDisplay()) {
                return false;
            } else if (!isHomeStack()){
                if (DEBUG_STATES) Slog.d(TAG_STATES,
                        "resumeTopActivityLocked: Launching home next");
                final int returnTaskType = prevTask == null || !prevTask.isOverHomeStack() ?
                        HOME_ACTIVITY_TYPE : prevTask.getTaskToReturnTo();
                return isOnHomeDisplay() &&
                        mStackSupervisor.resumeHomeStackTask(returnTaskType, prev, "prevFinished");
            }
        }
    
        // 如果ActivityManagerService处于休眠状态,而且此时没有Activity处于resume状态
        // 且栈顶Activity处于pause状态,则中断调度
        if (mService.isSleepingOrShuttingDown()
                && mLastPausedActivity == next
                && mStackSupervisor.allPausedActivitiesComplete()) {
            // Make sure we have executed any pending transitions, since there
            // should be nothing left to do at this point.
            mWindowManager.executeAppTransition();
            mNoAnimActivities.clear();
            ActivityOptions.abort(options);
            if (DEBUG_STATES) Slog.d(TAG_STATES,
                    "resumeTopActivityLocked: Going to sleep and all paused");
            if (DEBUG_STACK) mStackSupervisor.validateTopActivitiesLocked();
            return false;
        }
    
        // Make sure that the user who owns this activity is started.  If not,
        // we will just leave it as is because someone should be bringing
        // another user's activities to the top of the stack.
        if (mService.mStartedUsers.get(next.userId) == null) {
            Slog.w(TAG, "Skipping resume of top activity " + next
                    + ": user " + next.userId + " is stopped");
            if (DEBUG_STACK) mStackSupervisor.validateTopActivitiesLocked();
            return false;
        }
    
        // 确保我们要启动的Activity没有处于stop队列、休眠队列、等待变为可见队列中
        mStackSupervisor.mStoppingActivities.remove(next);
        mStackSupervisor.mGoingToSleepActivities.remove(next);
        next.sleeping = false;
        mStackSupervisor.mWaitingVisibleActivities.remove(next);
    
        if (DEBUG_SWITCH) Slog.v(TAG_SWITCH, "Resuming " + next);
    
        // If we are currently pausing an activity, then don't do anything
        // until that is done.
        if (!mStackSupervisor.allPausedActivitiesComplete()) {
            if (DEBUG_SWITCH || DEBUG_PAUSE || DEBUG_STATES) Slog.v(TAG_PAUSE,
                    "resumeTopActivityLocked: Skip resume: some activity pausing.");
            if (DEBUG_STACK) mStackSupervisor.validateTopActivitiesLocked();
            return false;
        }
    
    ……待续……
    }
    

    紧接上面的代码在后续的工作就是:将Launcher切换到pause状态,用WindowManager将Launcher的窗口隐藏。

    现在只完成了Activity相关的预处理工作,目标应用的进程和主线程还没有创建,因此后面会进入if的false分支调用mStackSupervisor.startSpecificActivityLocked方法创建应用进程;如果目标Activity的进程和主线程已经创建,则进入if语句的true分支直接将目标Activity切换到resume状态,并显示目标Activity的窗口。此流程看下面的代码:(上面的代码后续)

    private boolean resumeTopActivityInnerLocked(ActivityRecord prev, Bundle options) {
    
    ……续上……
    
        // 步入setLaunchSource方法后可以知道,该方法实际是通过PowerManager的setWorkSource方法
        // 设置WakeLock,使得在执行后面的工作时系统不会进入休眠状态
        mStackSupervisor.setLaunchSource(next.info.applicationInfo.uid);
    
        // 现在开始将当前Activity切换到pause状态,使得栈顶Activity可以切换到resume状态
        boolean dontWaitForPause = (next.info.flags&ActivityInfo.FLAG_RESUME_WHILE_PAUSING) != 0;
        // 将后台ActivityStack的Activity切换到pause状态
        boolean pausing = mStackSupervisor.pauseBackStacks(userLeaving, true, dontWaitForPause);
        // 将当前ActivityStack中正在显示Activity切换到pause状态
        if (mResumedActivity != null) {
            if (DEBUG_STATES) Slog.d(TAG_STATES,
                    "resumeTopActivityLocked: Pausing " + mResumedActivity);
            pausing |= startPausingLocked(userLeaving, false, true, dontWaitForPause);
        }
        if (pausing) {
            if (DEBUG_SWITCH || DEBUG_STATES) Slog.v(TAG_STATES,
                    "resumeTopActivityLocked: Skip resume: need to start pausing");
            // At this point we want to put the upcoming activity's process
            // at the top of the LRU list, since we know we will be needing it
            // very soon and it would be a waste to let it get killed if it
            // happens to be sitting towards the end.
            if (next.app != null && next.app.thread != null) {
                mService.updateLruProcessLocked(next.app, true, null);
            }
            if (DEBUG_STACK) mStackSupervisor.validateTopActivitiesLocked();
            return true;
        }
    
    ……
    
        ActivityStack lastStack = mStackSupervisor.getLastStack();
        if (next.app != null && next.app.thread != null) {
            if (DEBUG_SWITCH) Slog.v(TAG_SWITCH, "Resume running: " + next);
    
            // 目标Activity已经可见
            mWindowManager.setAppVisibility(next.appToken, true);
    
            next.startLaunchTickingLocked();
    
            ActivityRecord lastResumedActivity =
                    lastStack == null ? null :lastStack.mResumedActivity;
            ActivityState lastState = next.state;
    
            mService.updateCpuStats();
    
            // 目标Activity切换到resume状态
            if (DEBUG_STATES) Slog.v(TAG_STATES, "Moving to RESUMED: " + next + " (in existing)");
            next.state = ActivityState.RESUMED;
            mResumedActivity = next;
            next.task.touchActiveTime();
            mRecentTasks.addLocked(next.task);
            mService.updateLruProcessLocked(next.app, true, null);
            updateLRUListLocked(next);
            mService.updateOomAdjLocked();
    
    ……
            mStackSupervisor.startSpecificActivityLocked(next, true, true);
        }
    ……
    }
    

    接下来ActivityManagerService就要为即将打开的应用创建进程。

    进入ActivityStackSupervisor类的startSpecificActivityLocked方法,首先通过应用的包名和uid取得ProcessRecord,判断ProcessRecord是否被创建,若创建,则直接启动Activity;否则调用ActivityManagerService的startProcessLocked方法创建应用进程:

    void startSpecificActivityLocked(ActivityRecord r,
            boolean andResume, boolean checkConfig) {
        // Is this activity's application already running?
        ProcessRecord app = mService.getProcessRecordLocked(r.processName,
                r.info.applicationInfo.uid, true);
    
        r.task.stack.setLaunchTime(r);
    
        if (app != null && app.thread != null) {
            try {
                if ((r.info.flags&ActivityInfo.FLAG_MULTIPROCESS) == 0
                        || !"android".equals(r.info.packageName)) {
                    // Don't add this if it is a platform component that is marked
                    // to run in multiple processes, because this is actually
                    // part of the framework so doesn't make sense to track as a
                    // separate apk in the process.
                    app.addPackage(r.info.packageName, r.info.applicationInfo.versionCode,
                            mService.mProcessStats);
                }
                realStartActivityLocked(r, app, andResume, checkConfig);
                return;
            } catch (RemoteException e) {
                Slog.w(TAG, "Exception when starting activity "
                        + r.intent.getComponent().flattenToShortString(), e);
            }
    
            // If a dead object exception was thrown -- fall through to
            // restart the application.
        }
    
        mService.startProcessLocked(r.processName, r.info.applicationInfo, true, 0,
                "activity", r.intent.getComponent(), false, false, true);
    }
    

    进入到ActivityManagerService的startProcessLocked方法,首先判断要创建的进程是否为隔离进程(isolated),由于不是隔离进程,则直接进入true分支,然后再次获取ProcessRecord。如果Intent有FLAG_FROM_BACKGROUND标记,则在后台启动badProcess;否则清空进程的崩溃次数,并将进程移出badProcess集合(如果进程存在的话)。然后调用newProcessRecordLocked方法创建ProcessRecord,最后再调用另一个重载的startProcessLocked方法创建进程:

    final ProcessRecord startProcessLocked(String processName, ApplicationInfo info,
            boolean knownToBeDead, int intentFlags, String hostingType, ComponentName hostingName,
            boolean allowWhileBooting, boolean isolated, int isolatedUid, boolean keepIfLarge,
            String abiOverride, String entryPoint, String[] entryPointArgs, Runnable crashHandler) {
        long startTime = SystemClock.elapsedRealtime();
        ProcessRecord app;
        if (!isolated) {
            app = getProcessRecordLocked(processName, info.uid, keepIfLarge);
            checkTime(startTime, "startProcess: after getProcessRecord");
    
            if ((intentFlags & Intent.FLAG_FROM_BACKGROUND) != 0) {
                // If we are in the background, then check to see if this process
                // is bad.  If so, we will just silently fail.
                if (mBadProcesses.get(info.processName, info.uid) != null) {
                    if (DEBUG_PROCESSES) Slog.v(TAG, "Bad process: " + info.uid
                            + "/" + info.processName);
                    return null;
                }
            } else {
                // When the user is explicitly starting a process, then clear its
                // crash count so that we won't make it bad until they see at
                // least one crash dialog again, and make the process good again
                // if it had been bad.
                if (DEBUG_PROCESSES) Slog.v(TAG, "Clearing bad process: " + info.uid
                        + "/" + info.processName);
                mProcessCrashTimes.remove(info.processName, info.uid);
                if (mBadProcesses.get(info.processName, info.uid) != null) {
                    EventLog.writeEvent(EventLogTags.AM_PROC_GOOD,
                            UserHandle.getUserId(info.uid), info.uid,
                            info.processName);
                    mBadProcesses.remove(info.processName, info.uid);
                    if (app != null) {
                        app.bad = false;
                    }
                }
            }
        } else {
            // If this is an isolated process, it can't re-use an existing process.
            app = null;
        }
    
    ……
    
        String hostingNameStr = hostingName != null
                ? hostingName.flattenToShortString() : null;
    
        if (app == null) {
            checkTime(startTime, "startProcess: creating new process record");
            app = newProcessRecordLocked(info, processName, isolated, isolatedUid);
            if (app == null) {
                Slog.w(TAG, "Failed making new process record for "
                        + processName + "/" + info.uid + " isolated=" + isolated);
                return null;
            }
            app.crashHandler = crashHandler;
            checkTime(startTime, "startProcess: done creating new process record");
        } else {
            // If this is a new package in the process, add the package to the list
            app.addPackage(info.packageName, info.versionCode, mProcessStats);
            checkTime(startTime, "startProcess: added package to existing proc");
        }
    
        // 如果系统还没启动完毕,则等待系统启动完毕后再启动进程
        if (!mProcessesReady
                && !isAllowedWhileBooting(info)
                && !allowWhileBooting) {
            if (!mProcessesOnHold.contains(app)) {
                mProcessesOnHold.add(app);
            }
            if (DEBUG_PROCESSES) Slog.v(TAG_PROCESSES,
                    "System not ready, putting on hold: " + app);
            checkTime(startTime, "startProcess: returning with proc on hold");
            return app;
        }
    
        checkTime(startTime, "startProcess: stepping in to startProcess");
        startProcessLocked(
                app, hostingType, hostingNameStr, abiOverride, entryPoint, entryPointArgs);
        checkTime(startTime, "startProcess: done starting proc!");
        return (app.pid != 0) ? app : null;
    }
    

    调用newProcessRecordLocked方法根据ApplicationInfo创建ProcessRecord,并让ActivityManagerService管理该ProcessRecord,过程比较简单就不贴代码了,直接看startProcessLocked(app, hostingType, hostingNameStr, abiOverride, entryPoint, entryPointArgs)方法。

    进入startProcessLocked方法,首先将app的pid初始化,若进程已经存在(pid不等于0),则先清除超时信息,再讲pid置为0,然后确保app不在mProcessesOnHold列表中。

    mProcessesOnHold代表在系统启动完毕前尝试启动的进程,这部分进程会先在该列表中待着,等到系统启动完毕再启动。

    完成一系列的初始化操作后,调用Process.start方法创建应用进程,然后以进程pid为key,app(ProcessRecord)为value存储到ActivityManagerService的mPidsSelfLocked中。

    Process.start方法创建应用进程是通过Zygote进程完成的,设置好参数和创建选项后通过zygoteState.writer将数据交给Zygote进程,它会调用fork()创建进程。

    在这里要注意一个地方,我们通过if (entryPoint == null) entryPoint = "android.app.ActivityThread"这行代码设置了进程创建完成后的入口点(Process.start的参数注释),因此Zygote进程完成了进程创建的操作后就会执行ActivityThread的main()方法。

    下面看startProcessLocked的代码:

    private final void startProcessLocked(ProcessRecord app, String hostingType,
            String hostingNameStr, String abiOverride, String entryPoint, String[] entryPointArgs) {
        long startTime = SystemClock.elapsedRealtime();
        if (app.pid > 0 && app.pid != MY_PID) {
            checkTime(startTime, "startProcess: removing from pids map");
            synchronized (mPidsSelfLocked) {
                mPidsSelfLocked.remove(app.pid);
                mHandler.removeMessages(PROC_START_TIMEOUT_MSG, app);
            }
            checkTime(startTime, "startProcess: done removing from pids map");
            app.setPid(0);
        }
    
        if (DEBUG_PROCESSES && mProcessesOnHold.contains(app)) Slog.v(TAG_PROCESSES,
                "startProcessLocked removing on hold: " + app);
        mProcessesOnHold.remove(app);
    ……
    
            // Start the process.  It will either succeed and return a result containing
            // the PID of the new process, or else throw a RuntimeException.
            boolean isActivityProcess = (entryPoint == null);
            if (entryPoint == null) entryPoint = "android.app.ActivityThread";
            Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "Start proc: " +
                    app.processName);
            checkTime(startTime, "startProcess: asking zygote to start proc");
            Process.ProcessStartResult startResult = Process.start(entryPoint,
                    app.processName, uid, uid, gids, debugFlags, mountExternal,
                    app.info.targetSdkVersion, app.info.seinfo, requiredAbi, instructionSet,
                    app.info.dataDir, entryPointArgs);
    ……
    }
    

    进入到ActivityThread的main方法以后,首先进行一些初始化(包括参数设置、性能安全监控之类的),然后初始化Looper(Looper、Handler消息机制),创建ActivityThread,存储线程的Handler,最后启动Looper监听消息。

    再之后ActivityThread通过Binder将ApplicationThread对象传递给ActivityManagerService,并完成启动Activity的后续工作。

    到这里ActivityThread的初始化就完成了,但是回想一下前面的工作,我们现在将Launcher切换到了pause状态,但由于目标应用进程和线程还没有创建,所以我们还没有把目标应用的MainActivity切换到resume状态。所以就意味着,我们还需要进行应用进程和ActivityManagerService所在的system_server进程的通信,告诉ActivityManagerService我们已经创建好了进程和线程,接下来把MainActivity状态切换到resume中,就能打开应用了。

    这一步工作在哪里完成的呢:thread.attach(false)

    final IActivityManager mgr = ActivityManagerNative.getDefault();看到这行代码有没有熟悉的感觉?前面我们就通过ActivityManagerNative.getDefault()取得ActivityManagerService的代理对象,完成了启动MainActivity的前期工作。这里再次取得代理对象,并调用了ActivityManagerService的attachApplication方法。

    public static void main(String[] args) {
    ……
    
        Process.setArgV0("<pre-initialized>");
    
        Looper.prepareMainLooper();
    
        ActivityThread thread = new ActivityThread();
        thread.attach(false);
    
        if (sMainThreadHandler == null) {
            sMainThreadHandler = thread.getHandler();
        }
    
        if (false) {
            Looper.myLooper().setMessageLogging(new
                    LogPrinter(Log.DEBUG, "ActivityThread"));
        }
    
        // End of event ActivityThreadMain.
        Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
        Looper.loop();
    
        throw new RuntimeException("Main thread loop unexpectedly exited");
    }
    
    private void attach(boolean system) {
        sCurrentActivityThread = this;
        mSystemThread = system;
        if (!system) {
            ViewRootImpl.addFirstDrawHandler(new Runnable() {
                @Override
                public void run() {
                    ensureJitEnabled();
                }
            });
            android.ddm.DdmHandleAppName.setAppName("<pre-initialized>",
                                                    UserHandle.myUserId());
            RuntimeInit.setApplicationObject(mAppThread.asBinder());
            final IActivityManager mgr = ActivityManagerNative.getDefault();
            try {
                mgr.attachApplication(mAppThread);
            } catch (RemoteException ex) {
                // Ignore
            }
    ……
        } else {
    ……
        }
    ……
    }
    

    进入到ActivityManagerService的attachApplication方法,前面我们已经存储过目标应用的pid-ProcessRecord键值对了,因此这里的app不为null。然后向下执行,激活ProcessRecord并将ProcessRecord绑定到应用进程。然后通过Binder(thread.bindApplication)将各种应用相关信息传递给应用进程,进行应用进程一些必要的设置。最后调用mStackSupervisor.attachApplicationLocked(app)方法将ApplicationThread对象传递给ActivityManagerService方便后续应用进程与ActivityManagerService的通信(如:将MainActivity切换到resume状态),并完成启动应用的所有工作。

    @Override
    public final void attachApplication(IApplicationThread thread) {
        synchronized (this) {
            int callingPid = Binder.getCallingPid();
            final long origId = Binder.clearCallingIdentity();
            attachApplicationLocked(thread, callingPid);
            Binder.restoreCallingIdentity(origId);
        }
    }
    
    private final boolean attachApplicationLocked(IApplicationThread thread,
            int pid) {
    
        // Find the application record that is being attached...  either via
        // the pid if we are running in multiple processes, or just pull the
        // next app record if we are emulating process with anonymous threads.
        ProcessRecord app;
        if (pid != MY_PID && pid >= 0) {
            synchronized (mPidsSelfLocked) {
                app = mPidsSelfLocked.get(pid);
            }
        } else {
            app = null;
        }
    
        // 此时app不为null,跳过
        if (app == null) {
    ……
        }
    
        // 清除ProcessRecord中的信息,以确保没有不相关进程的信息
        if (app.thread != null) {
            handleAppDiedLocked(app, true, true);
        }
    
        // Tell the process all about itself.
    
        if (DEBUG_ALL) Slog.v(
                TAG, "Binding process pid " + pid + " to record " + app);
    
        // 注册DeathRecipient,确保应用意外关闭时系统进程能收到通知
        final String processName = app.processName;
        try {
            AppDeathRecipient adr = new AppDeathRecipient(
                    app, pid, thread);
            thread.asBinder().linkToDeath(adr, 0);
            app.deathRecipient = adr;
        } catch (RemoteException e) {
            app.resetPackageList(mProcessStats);
            startProcessLocked(app, "link fail", processName);
            return false;
        }
    
        EventLog.writeEvent(EventLogTags.AM_PROC_BOUND, app.userId, app.pid, app.processName);
    
        app.makeActive(thread, mProcessStats);
        app.curAdj = app.setAdj = -100;
        app.curSchedGroup = app.setSchedGroup = Process.THREAD_GROUP_DEFAULT;
        app.forcingToForeground = null;
        updateProcessForegroundLocked(app, false, false);
        app.hasShownUi = false;
        app.debugging = false;
        app.cached = false;
        app.killedByAm = false;
    
        mHandler.removeMessages(PROC_START_TIMEOUT_MSG, app);
    ……
        // 调用ActivityThread的bindApplication方法
        try {
    ……
            thread.bindApplication(processName, appInfo, providers, app.instrumentationClass,
                    profilerInfo, app.instrumentationArguments, app.instrumentationWatcher,
                    app.instrumentationUiAutomationConnection, testMode, enableOpenGlTrace,
                    isRestrictedBackupMode || !normalMode, app.persistent,
                    new Configuration(mConfiguration), app.compat,
                    getCommonServicesLocked(app.isolated),
                    mCoreSettingsObserver.getCoreSettingsLocked());
            updateLruProcessLocked(app, false, null);
            app.lastRequestedGc = app.lastLowMemory = SystemClock.uptimeMillis();
        } catch (Exception e) {
    ……
        }
    
    ……
    
        // See if the top visible activity is waiting to run in this process...
        if (normalMode) {
            try {
                if (mStackSupervisor.attachApplicationLocked(app)) {
                    didSomething = true;
                }
            } catch (Exception e) {
                Slog.wtf(TAG, "Exception thrown launching activities in " + app, e);
                badApp = true;
            }
        }
    
        // Find any services that should be running in this process...
        if (!badApp) {
    ……
        }
    
        // Check if a next-broadcast receiver is in this process...
        if (!badApp && isPendingBroadcastProcessLocked(pid)) {
    ……
        }
    
        // Check whether the next backup agent is in this process...
        if (!badApp && mBackupTarget != null && mBackupTarget.appInfo.uid == app.uid) {
    ……
        }
    
    ……
    
        return true;
    }
    

    后面就是ActivityManagerService通知ActivityThread启动Activity了。

    回到ActivityThread,先看bindApplication方法,就是将上面传的数据存储在AppBindData中,然后通过Message、Handler发送出去,我们再看看Handler是怎么处理H.BIND_APPLICATION类型的Message的。

    public final void bindApplication(String processName, ApplicationInfo appInfo,
            List<ProviderInfo> providers, ComponentName instrumentationName,
            ProfilerInfo profilerInfo, Bundle instrumentationArgs,
            IInstrumentationWatcher instrumentationWatcher,
            IUiAutomationConnection instrumentationUiConnection, int debugMode,
            boolean enableOpenGlTrace, boolean isRestrictedBackupMode, boolean persistent,
            Configuration config, CompatibilityInfo compatInfo, Map<String, IBinder> services,
            Bundle coreSettings) {
    ……
    
        AppBindData data = new AppBindData();
        data.processName = processName;
        data.appInfo = appInfo;
        data.providers = providers;
        data.instrumentationName = instrumentationName;
        data.instrumentationArgs = instrumentationArgs;
        data.instrumentationWatcher = instrumentationWatcher;
        data.instrumentationUiAutomationConnection = instrumentationUiConnection;
        data.debugMode = debugMode;
        data.enableOpenGlTrace = enableOpenGlTrace;
        data.restrictedBackupMode = isRestrictedBackupMode;
        data.persistent = persistent;
        data.config = config;
        data.compatInfo = compatInfo;
        data.initProfilerInfo = profilerInfo;
        sendMessage(H.BIND_APPLICATION, data);
    }
    
    case BIND_APPLICATION:
        Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "bindApplication");
        AppBindData data = (AppBindData)msg.obj;
        handleBindApplication(data);
        Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
        break;
    

    可以看到最终调用了handleBindApplication方法,进入到handleBindApplication方法,首先进行一些初始化操作,然后取出data中存储的进程名,为应用进程设置进程名。然后创建应用的Context,也就是应用的运行上下文,通过Context我们可以访问到应用相关的各种资源文件(图片、布局文件等等)。然后创建进程的Instrumentation对象、Application对象,装载Provider,最终调用mInstrumentation.callApplicationOnCreate(app)方法,也就是调用我们开发App时,Application类(或子类)的onCreate()方法。

    private void handleBindApplication(AppBindData data) {
    ……
    
        // send up app name; do this *before* waiting for debugger
        Process.setArgV0(data.processName);
        android.ddm.DdmHandleAppName.setAppName(data.processName,
                                                UserHandle.myUserId());
    
    ……设置进程运行信息……
    
        final ContextImpl appContext = ContextImpl.createAppContext(this, data.info);
    
    ……继续进程的初始化……
    
        if (data.instrumentationName != null) {
            ……
    
        } else {
            mInstrumentation = new Instrumentation();
        }
    
    ……
    
        try {
            // If the app is being launched for full backup or restore, bring it up in
            // a restricted environment with the base application class.
            Application app = data.info.makeApplication(data.restrictedBackupMode, null);
            mInitialApplication = app;
    
            // don't bring up providers in restricted mode; they may depend on the
            // app's custom Application class
            if (!data.restrictedBackupMode) {
                List<ProviderInfo> providers = data.providers;
                if (providers != null) {
                    installContentProviders(app, providers);
                    // For process that contains content providers, we want to
                    // ensure that the JIT is enabled "at some point".
                    mH.sendEmptyMessageDelayed(H.ENABLE_JIT, 10*1000);
                }
            }
    
    ……
    
            try {
                mInstrumentation.callApplicationOnCreate(app);
            } catch (Exception e) {
                if (!mInstrumentation.onException(app, e)) {
                    throw new RuntimeException(
                        "Unable to create application " + app.getClass().getName()
                        + ": " + e.toString(), e);
                }
            }
        } finally {
            StrictMode.setThreadPolicy(savedPolicy);
        }
    }
    

    至此应用进程相关的初始化和相关的设置就完成了,接下来只要切换MainActivity的状态就大功告成了。

    进入到ActivityStackSupervisor类的attachApplicationLocked方法,该方法遍历mActivityDisplays列表得到当前所有ActivityStack,然后取得前台ActivityStack栈顶的ActivityRecord,不为空则启动该对该ActivityRecord调用realStartActivityLocked方法。

    boolean attachApplicationLocked(ProcessRecord app) throws RemoteException {
        final String processName = app.processName;
        boolean didSomething = false;
        for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) {
            ArrayList<ActivityStack> stacks = mActivityDisplays.valueAt(displayNdx).mStacks;
            for (int stackNdx = stacks.size() - 1; stackNdx >= 0; --stackNdx) {
                final ActivityStack stack = stacks.get(stackNdx);
                if (!isFrontStack(stack)) {
                    continue;
                }
                ActivityRecord hr = stack.topRunningActivityLocked(null);
                if (hr != null) {
                    if (hr.app == null && app.uid == hr.info.applicationInfo.uid
                            && processName.equals(hr.processName)) {
                        try {
                            if (realStartActivityLocked(hr, app, true, true)) {
                                didSomething = true;
                            }
                        } catch (RemoteException e) {
                            Slog.w(TAG, "Exception in new application when starting activity "
                                  + hr.intent.getComponent().flattenToShortString(), e);
                            throw e;
                        }
                    }
                }
            }
        }
        if (!didSomething) {
            ensureActivitiesVisibleLocked(null, 0);
        }
        return didSomething;
    }
    

    到这里,后面就该ActivityThread调度执行Activity生命周期方法,完成Activity的启动。

    进入到realStartActivityLocked方法,进行一些前期处理后调用ActivityThread的scheduleLaunchActivity方法,将创建ActivityClientRecord存储我们传入的各种应用相关的数据,通过Handler机制发送。当Handler接收到LAUNCH_ACTIVITY类型的消息时,执行handleLaunchActivity方法。

    app.thread.scheduleLaunchActivity(new Intent(r.intent), r.appToken,
                        System.identityHashCode(r), r.info, new Configuration(mService.mConfiguration),
                        new Configuration(stack.mOverrideConfig), r.compat, r.launchedFromPackage,
                        task.voiceInteractor, app.repProcState, r.icicle, r.persistentState, results,
                        newIntents, !andResume, mService.isNextTransitionForward(), profilerInfo);
    
    @Override
    public final void scheduleLaunchActivity(Intent intent, IBinder token, int ident,
            ActivityInfo info, Configuration curConfig, Configuration overrideConfig,
            CompatibilityInfo compatInfo, String referrer, IVoiceInteractor voiceInteractor,
            int procState, Bundle state, PersistableBundle persistentState,
            List<ResultInfo> pendingResults, List<ReferrerIntent> pendingNewIntents,
            boolean notResumed, boolean isForward, ProfilerInfo profilerInfo) {
    
        updateProcessState(procState, false);
    
        ActivityClientRecord r = new ActivityClientRecord();
    
        r.token = token;
        r.ident = ident;
        r.intent = intent;
        r.referrer = referrer;
        r.voiceInteractor = voiceInteractor;
        r.activityInfo = info;
        r.compatInfo = compatInfo;
        r.state = state;
        r.persistentState = persistentState;
    
        r.pendingResults = pendingResults;
        r.pendingIntents = pendingNewIntents;
    
        r.startsNotResumed = notResumed;
        r.isForward = isForward;
    
        r.profilerInfo = profilerInfo;
    
        r.overrideConfig = overrideConfig;
        updatePendingConfiguration(curConfig);
    
        sendMessage(H.LAUNCH_ACTIVITY, r);
    }
    
    case LAUNCH_ACTIVITY: {
        Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "activityStart");
        final ActivityClientRecord r = (ActivityClientRecord) msg.obj;
    
        r.packageInfo = getPackageInfoNoCheck(
                r.activityInfo.applicationInfo, r.compatInfo);
        handleLaunchActivity(r, null);
        Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
    } break;
    

    进入到handleLaunchActivity方法,首先进行参数设置,然后调用performLaunchActivity方法得到目标应用的MainActivity并使其分别调用onCreate、onStart方法,然后调用handleResumeActivity方法让MainActivity进入resume状态,完成启动。

    private void handleLaunchActivity(ActivityClientRecord r, Intent customIntent) {
    ……
    
        Activity a = performLaunchActivity(r, customIntent);
    
        if (a != null) {
            r.createdConfig = new Configuration(mConfiguration);
            Bundle oldState = r.state;
            handleResumeActivity(r.token, false, r.isForward,
                    !r.activity.mFinished && !r.startsNotResumed);
    
    ……
        } else {
    ……
        }
    }
    
    private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
        // 初始化设置
    ……
    
        // 通过反射获得MainActivity
        Activity activity = null;
        try {
            java.lang.ClassLoader cl = r.packageInfo.getClassLoader();
            activity = mInstrumentation.newActivity(
                    cl, component.getClassName(), r.intent);
            StrictMode.incrementExpectedActivityCount(activity.getClass());
            r.intent.setExtrasClassLoader(cl);
            r.intent.prepareToEnterProcess();
            if (r.state != null) {
                r.state.setClassLoader(cl);
            }
        } catch (Exception e) {
            if (!mInstrumentation.onException(activity, e)) {
                throw new RuntimeException(
                    "Unable to instantiate activity " + component
                    + ": " + e.toString(), e);
            }
        }
    
        try {
    ……
    
            if (activity != null) {
                // 为MainActivity创建运行的上下文环境Context,并与Activity绑定
                Context appContext = createBaseContextForActivity(r, activity);
                CharSequence title = r.activityInfo.loadLabel(appContext.getPackageManager());
                Configuration config = new Configuration(mCompatConfiguration);
                if (DEBUG_CONFIGURATION) Slog.v(TAG, "Launching activity "
                        + r.activityInfo.name + " with config " + config);
                activity.attach(appContext, this, getInstrumentation(), r.token,
                        r.ident, app, r.intent, r.activityInfo, title, r.parent,
                        r.embeddedID, r.lastNonConfigurationInstances, config,
                        r.referrer, r.voiceInteractor);
    
    ……
                // 回调MainActivity生命周期的onCreate方法
                if (r.isPersistable()) {
                    mInstrumentation.callActivityOnCreate(activity, r.state, r.persistentState);
                } else {
                    mInstrumentation.callActivityOnCreate(activity, r.state);
                }
    ……
                // 回调MainActivity生命周期的onStart方法
                if (!r.activity.mFinished) {
                    activity.performStart();
                    r.stopped = false;
                }
    ……
    
        } catch (SuperNotCalledException e) {
            throw e;
    
        } catch (Exception e) {
            if (!mInstrumentation.onException(activity, e)) {
                throw new RuntimeException(
                    "Unable to start activity " + component
                    + ": " + e.toString(), e);
            }
        }
    
        return activity;
    }
    
    final void handleResumeActivity(IBinder token,
            boolean clearHide, boolean isForward, boolean reallyResume) {
        // If we are getting ready to gc after going to the background, well
        // we are back active so skip it.
        unscheduleGcIdler();
        mSomeActivitiesChanged = true;
    
        // TODO Push resumeArgs into the activity for consideration
        ActivityClientRecord r = performResumeActivity(token, clearHide);
    
    ……
    }
    

    好了,到了这里,apk启动流程的源码分析就算是完成了,咱们已经对apk的启动流程有清晰的认知和理解了。

    最后总结一下app启动步骤:

    (1)启动的起点发生在Launcher活动中,启动一个app说简单点就是启动一个Activity,那么我们说过所有组件的启动,切换,调度都由AMS来负责的,所以第一步就是Launcher响应了用户的点击事件,然后通知AMS;

    (2)AMS得到Launcher的通知,就需要响应这个通知,主要就是新建一个Task去准备启动Activity,并且告诉Launcher你可以休息了(Paused);

    (3)Launcher得到AMS让自己“休息”的消息,那么就直接挂起,并告诉AMS我已经Paused了;

    (4)AMS知道了Launcher已经挂起之后,就可以放心的为新的Activity准备启动工作了,首先,APP肯定需要一个新的进程去进行运行,所以需要创建一个新进程,这个过程是需要Zygote参与的,AMS通过Socket去和Zygote协商,如果需要创建进程,那么就会fork自身,创建一个线程,新的进程会导入ActivityThread类,这就是每一个应用程序都有一个ActivityThread与之对应的原因;

    (5)进程创建好了,通过调用上述的ActivityThread的main方法,这是应用程序的入口,在这里开启消息循环队列,这也是主线程默认绑定Looper的原因;

    (6)这时候,App还没有启动完,要永远记住,四大组建的启动都需要AMS去启动,将上述的应用进程信息注册到AMS中,AMS再在堆栈顶部取得要启动的Activity,通过一系列链式调用去完成App启动;
    最后copy这张图很好的描述了上面的六大步:

     
    

    好了,本文结束了  see  you

    展开全文
  • APP启动分析 Cold start At the beginning of a cold start, the system has three tasks. These tasks are: 1、Loading and launching the app. 2、Displaying a blank starting window for the app immediately ...

    APP启动分析

    Cold start

    At the beginning of a cold start, the system has three tasks. These tasks are:

    1、Loading and launching the app.
    2、Displaying a blank starting window for the app immediately after launch
    3、.Creating the app process.

    As soon as the system creates the app process, the app process is responsible for the next stages:

    1、Creating the app object.
    2、Launching the main thread.
    3、Creating the main activity.
    4、Inflating views.
    5、Laying out the screen.
    6、Performing the initial draw.

    系统和应用之间交互简图

    在这里插入图片描述

    Application creation

    When your application launches, the blank starting window remains on the screen until the system finishes drawing the app for the first time. At that point, the system process swaps out the starting window for your app, allowing the user to start interacting with the app.
    If you’ve overloaded Application.onCreate() in your own app, the system invokes the onCreate() method on your app object. Afterwards, the app spawns the main thread, also known as the UI thread, and tasks it with creating your main activity.

    From this point, system- and app-level processes proceed in accordance with the app lifecycle stages.

    Activity creation

    After the app process creates your activity, the activity performs the following operations:

    1、Initializes values.
    2、Calls constructors.
    3、Calls the callback method, such as Activity.onCreate(), appropriate to the current lifecycle state of the activity.

    Typically, the onCreate() method has the greatest impact on load time, because it performs the work with the highest overhead: loading and inflating views, and initializing the objects needed for the activity to run.

    Hot start

    A hot start of your application is much simpler and lower-overhead than a cold start. In a hot start, all the system does is bring your activity to the foreground. If all of your application’s activities are still resident in memory, then the app can avoid having to repeat object initialization, layout inflation, and rendering.However, if some memory has been purged in response to memory trimming events, such as onTrimMemory(), then those objects will need to be recreated in response to the hot start event.
    A hot start displays the same on-screen behavior as a cold start scenario: The system process displays a blank screen until the app has finished rendering the activity.

    Warm start

    A warm start encompasses some subset of the operations that take place during a cold start; at the same time, it represents more overhead than a hot start. There are many potential states that could be considered warm starts.
    For instance:

    • The user backs out of your app, but then re-launches it. The process may have continued to run, but the app must recreate the activity from scratch via a call to onCreate().
    • The system evicts your app from memory, and then the user re-launches it. The process and the activity need to be restarted, but the task can benefit somewhat from the saved instance state bundle passed into onCreate().

    译文

    冷启动

    简单讲app冷启动可以分为两个阶段
    第一阶段

    1、加载并启动app
    2、启动后立即显示一个空白的启动窗口
    3、创建app进程

    第二阶段

    1、创建app对象
    2、启动主进程
    3、创建MainActivity
    4、渲染视图
    5、执行onLayout
    6、执行onDraw

    应用创建
    当应用程序启动时,空白的开始窗口将保留在屏幕上,直到系统第一次绘制完应用程序。此时,系统进程会为应用程序交换启动窗口,允许用户开始与应用程序交互

    之后按照app生命周期依次执行

    简单说就是当屏幕上的组件渲染结束后,用app窗口替换系统空白窗口,此时允许用户与app进行交互

    Activity创建

    1、初始化values
    2、初始化构造方法
    3、执行生命周期回调

    热启动

    热启动时,系统将activity放到前台。如果应用程序的所有activity存在内存中,则应用程序可以避免重复对象初始化、渲染、绘制操作。

    如果由于内存不足导致对象被回收,则需要在热启动时重建对象,此时与冷启动时将界面显示到手机屏幕上一样。

    温启动

    温启动时由于app的进程仍然存在,只执行冷启动第二阶段流程

    1、创建app对象
    2、启动主进程
    3、创建MainActivity
    4、渲染视图
    5、执行onLayout
    6、执行onDraw

    温启动常见场景:

    1、用户双击返回键退出应用
    2、app由于内存不足被回收

    展开全文
  • APP启动流程解析

    万次阅读 多人点赞 2019-04-22 10:07:15
    启动流程简介 首先要知道的是,手机屏幕其实就是一个Activity,我们专业点将其称为Launcher,相信做过车载设备开发的朋友肯定不会陌生,Launcher是手机厂商提供的,不同的手机厂商比拼的就是Launcher的设计。当然...

    前言

    当我们点击手机屏幕上的软件图标时,就可以打开这个软件,看似很简单的过程其实包含了许多的底层交互,看了还不明白,欢迎来打我。

    一 . 启动流程简介

    首先要知道的是,手机屏幕其实就是一个Activity,我们专业点将其称为Launcher,相信做过车载设备开发的朋友肯定不会陌生,Launcher是手机厂商提供的,不同的手机厂商比拼的就是Launcher的设计。当然我们自己也可以去编写Launcher,运行在手机上使用自己的桌面风格,当然这里我们不去讲如何去编写一个Launcher,如果你感兴趣欢迎关注我。

    写过AndroidDemo的朋友肯定都知道,我们必须在AndroidManifest配置文件中配置默认启动的Activity

    <intent-filter>
        <action android:name="android.intent.action.MAIN" />
    
        <category android:name="android.intent.category.LAUNCHER" />
    </intent-filter>

    其实就是告诉Launcher该启动这个App的哪个页面。这样当系统启动的时候,PackageManger-Service就可以从配置文件中读取到该启动哪个Activity。

    其次要知道的是,Launch和其他APP,运行在不同的进程中,所以他们之间的通信是通过Binder去完成的,所以AMS是必不可少的。下面我们以启动微信为例,看看启动流程是怎样的。

                               

                                                 

                                                                 

                                           

                                                                              

                    

                                                                    

              

                                                                 

             

    简单概括启动微信的流程就是:

    1.Launcher通知AMS 要启动微信了,并且告诉AMS要启动的是哪个页面也就是首页是哪个页面

    2.AMS收到消息告诉Launcher知道了,并且把要启动的页面记下来

    3.Launcher进入Paused状态,告诉AMS,你去找微信吧

    上述就是Launcher和AMS的交互过程

    4.AMS检查微信是否已经启动了也就是是否在后台运行,如果是在后台运行就直接启动,如果不是,AMS会在新的进程中创建一个ActivityThread对象,并启动其中的main函数。

    5.微信启动后告诉AMS,启动好了

    6.AMS通过之前的记录找出微信的首页,告诉微信应该启动哪个页面

    7.微信按照AMS通知的页面去启动就启动成功了。

          

    上述阶段是微信和AMS的交互过程。那么接下来我们分析下具体过程

    二  启动流程分析

    1.点击Launcher上的微信图标时,会调用startActivitySafely方法,intent中携带微信的关键信息也就是我们在配置文件中配置的默认启动页信息,其实在微信安装的时候,Launcher已经将启动信息记录下来了,图标只是一个快捷方式的入口。

    startActivitySafely的方法最终还是会调用Activity的startActivity方法

    @Override
    public void startActivity(Intent intent, @Nullable Bundle options) {
        if (options != null) {
            startActivityForResult(intent, -1, options);
        } else {
            // Note we want to go through this call for compatibility with
            // applications that may have overridden the method.
            startActivityForResult(intent, -1);
        }
    }

    而startActivity方法最终又会回到startActivityForResult方法,这里startActivityForResult的方法中code为-1,表示startActivity并不关心是否启动成功。startActivityForResult部分方法如下所示:

    public void startActivityForResult(@RequiresPermission Intent intent, int requestCode,
            @Nullable Bundle options) {
        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) {

    startActivityForResult方法中又会调用mInstrumentation.execStartActivity方法,我们看到其中有个参数是

    mMainThread.getApplicationThread()

    关于ActivityThread曾在 深入理解Android消息机制https://blog.csdn.net/huangliniqng文章中提到过,ActivityThread是在启动APP的时候创建的,ActivityThread代表应用程序,而我们开发中常用的Application其实是ActivityThread的上下文,在开发中我们经常使用,但在Android系统中其实地位很低的。

                                                             

    Android的main函数就在ActivityThread中

    public static void main(String[] args) {
        Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "ActivityThreadMain");
        SamplingProfilerIntegration.start();
    
        // CloseGuard defaults to true and can be quite spammy.  We
        // disable it here, but selectively enable it later (via
        // StrictMode) on debug builds, but using DropBox, not logs.
        CloseGuard.setEnabled(false);
    
        Environment.initForCurrentUser();

    再回到上面方法

    mMainThread.getApplicationThread()
    

    得到的是一个Binder对象,代表Launcher所在的App的进程,mToken实际也是一个Binder对象,代表Launcher所在的Activity通过Instrumentation传给AMS,这样AMS就知道是谁发起的请求。

    2.mInstrumentation.execStartActivity

    instrumentation在测试的时候经常用到,instrumentation的官方文档:http://developer.android.com/intl/zh-cn/reference/android/app/Instrumentation.html这里不对instrumentation进行详细介绍了,我们主要接着看mInstrumentation.execStartActivity方法

    public Instrumentation.ActivityResult execStartActivity(Context who, IBinder contextThread, IBinder token, Activity target, Intent intent, int requestCode, Bundle options) {
        IApplicationThread whoThread = (IApplicationThread)contextThread;
        if(this.mActivityMonitors != null) {
            Object e = this.mSync;
            synchronized(this.mSync) {
                int N = this.mActivityMonitors.size();
    
                for(int i = 0; i < N; ++i) {
                    Instrumentation.ActivityMonitor am = (Instrumentation.ActivityMonitor)this.mActivityMonitors.get(i);
                    if(am.match(who, (Activity)null, intent)) {
                        ++am.mHits;
                        if(am.isBlocking()) {
                            return requestCode >= 0?am.getResult():null;
                        }
                        break;
                    }
                }
            }
        }
    
        try {
            intent.setAllowFds(false);
            intent.migrateExtraStreamToClipData();
            int var16 = ActivityManagerNative.getDefault().startActivity(whoThread, intent, intent.resolveTypeIfNeeded(who.getContentResolver()), token, target != null?target.mEmbeddedID:null, requestCode, 0, (String)null, (ParcelFileDescriptor)null, options);
            checkStartActivityResult(var16, intent);
        } catch (RemoteException var14) {
            ;
        }
    
        return null;
    }

    其实这个类是一个Binder通信类,相当于IPowerManager.java就是实现了IPowerManager.aidl,我们再来看看getDefault这个函数

    public static IActivityManager getDefault() {
        return (IActivityManager)gDefault.get();
    }

    getDefault方法得到一个IActivityManager,它是一个实现了IInterface的接口,里面定义了四大组件的生命周期,

    public static IActivityManager asInterface(IBinder obj) {
        if(obj == null) {
            return null;
        } else {
            IActivityManager in = (IActivityManager)obj.queryLocalInterface("android.app.IActivityManager");
            return (IActivityManager)(in != null?in:new ActivityManagerProxy(obj));
        }
    }

    最终返回一个ActivityManagerProxy对象也就是AMP,AMP就是AMS的代理对象,说到代理其实就是代理模式,关于什么是代理模式以及动态代理和静态代理的使用可以持续关注我,后面会单独写篇文章进行介绍。

                

    AMP的startActivity方法

    public int startActivity(IApplicationThread caller, Intent intent, String resolvedType, IBinder resultTo, String resultWho, int requestCode, int startFlags, String profileFile, ParcelFileDescriptor profileFd, Bundle options) throws RemoteException {
        Parcel data = Parcel.obtain();
        Parcel reply = Parcel.obtain();
        data.writeInterfaceToken("android.app.IActivityManager");
        data.writeStrongBinder(caller != null?caller.asBinder():null);
        intent.writeToParcel(data, 0);
        data.writeString(resolvedType);
        data.writeStrongBinder(resultTo);
        data.writeString(resultWho);
        data.writeInt(requestCode);
        data.writeInt(startFlags);
        data.writeString(profileFile);
        if(profileFd != null) {
            data.writeInt(1);
            profileFd.writeToParcel(data, 1);
        } else {
            data.writeInt(0);
        }

    主要就是将数据写入AMS进程,等待AMS的返回结果,这个过程是比较枯燥的,因为我们做插件化的时候只能对客户端Hook,而不能对服务端操作,所以我们只能静静的看着。(温馨提示:如果文章到这儿你已经有点头晕了,那就对了,研究源码主要就是梳理整个流程,千万不要纠结源码细节,那样会无法自拔)。

    3.AMS处理Launcher的信息

    AMS告诉Launcher我知道了,那么AMS如何告诉Launcher呢?

    Binder的通信是平等的,谁发消息谁就是客户端,接收的一方就是服务端,前面已经将Launcher所在的进程传过来了,AMS将其保存为一个ActivityRecord对象,这个对象中有一个ApplicationThreadProxy即Binder的代理对象,AMS通ApplicationTreadProxy发送消息,App通过ApplicationThread来接收这个消息。

    Launcher收到消息后,再告诉AMS,好的我知道了,那我走了,ApplicationThread调用ActivityThread的sendMessage方法给Launcher主线程发送一个消息。这个时候AMS去启动一个新的进程,并且创建ActivityThread,指定main函数入口。

    启动新进程的时候为进程创建了ActivityThread对象,这个就是UI线程,进入main函数后,创建一个Looper,也就是mainLooper,并且创建Application,所以说Application只是对开发人员来说重要而已。创建好后告诉AMS微信启动好了,AMS就记录了这个APP的登记信息,以后AMS通过这个ActivityThread向APP发送消息。

    这个时候AMS根据之前的记录告诉微信应该启动哪个Activity,微信就可以启动了。

    public void handleMessage(Message msg) {
        ActivityThread.ActivityClientRecord data;
        switch(msg.what) {
        case 100:
            Trace.traceBegin(64L, "activityStart");
            data = (ActivityThread.ActivityClientRecord)msg.obj;
            data.packageInfo = ActivityThread.this.getPackageInfoNoCheck(data.activityInfo.applicationInfo, data.compatInfo);
            ActivityThread.this.handleLaunchActivity(data, (Intent)null);
            Trace.traceEnd(64L);
    ActivityThread.ActivityClientRecord

    就是AMS传过来的Activity

    data.activityInfo.applicationInfo

    所得到的属性我们称之为LoadedApk,可以提取到apk中的所有资源,那么APP内部是如何页面跳转的呢,比如我们从ActivityA跳转到ActivityB,我们可以将Activity看作Launcher,唯一不同的就是,在正常情况下ActivityB和ActivityA所在同一进程,所以不会去创建新的进程。

    APP的启动流程就是这样了,欢迎留言探讨,记得持续关注哦。

    展开全文
  • android-App启动过程

    千次阅读 2018-09-24 00:17:04
    APP启动流程涉及的类和调用的方法还是蛮多的,做为android应用开发其实知道整个流程和重要的调用方法就够了。但是在了解整个流程前,得先知道涉及的相关知识,这样才能更好理解后面整个流程。后面源码分析基于...

    前言

    APP启动流程涉及的类和调用的方法还是蛮多的,做为android应用开发其实知道整个流程和重要的调用方法就够了。但是在了解整个流程前,得先知道涉及的相关知识,这样才能更好理解后面整个流程。后面源码分析基于Android-2.2_r1。

    Zygote

    zygote名字翻译叫受精卵,首先要知道zygote进程的创建是由Linux系统中init进程创建的,Android中所有的进程都是直接或者间接的由init进程fork出来的,Zygote进程负责其他进程的创建和启动,比如创建SystemServer进程。当需要启动一个新的android应用程序的时候,ActivityManagerService就会通过Socket通知Zygote进程为这个应用创建一个新的进程

    Launcher

    我们要知道手机的桌面也是一个App我们叫它launcher,每一个手机应用都是在Launcher上显示,而Launcher的加载是在手机启动的时候加载Zygote,然后Zygote启动SystenServer,SystenServer会启动各种ManageService, 包括ActivityManagerService,并将这些ManageService注册到ServiceManage 容器中,然后ActivityManagerService就会启动Home应用程序Launcher.

    ActivityManagerService

    ActivityManagerService我们简称AMS,首先当我们看到名字的时候,我们以为他是管理Activity的,其实四大组件都归它管,四大组件的跨进程通信都要和它合作,后面讲Binder时候会提到它。
    AMS管理Activity主要是管理什么呢? 这就要说到AMS的相关类:

    • ProcessRecord 表示应用进程记录,每个应用进程都有对应的ProcessRecord对象
    • ActivityStack 该类主要管理回退栈
    • ActviityRecord 每次启动一个Activity会有一个对应的ActivityRecord对象,表示一个Activity的一个记录
    • ActivityInfo Activity信息,比如启动模式,taskAffinity,flag信息
    • TaskRecord Task记录信息,一个Task可能有多个ActivityRecord,但是一个ActivityRecord只能属于一个TaskRecord

    Binder

    Binder是Android跨进程通信(IPC)的一种方式,也是Android系统中最重要的特性之一,android 四大组件以及不同的App都运行在不同的进程,它则是各个进程的桥梁将不同的进程粘合在一起。
    学习Binder首先要知道相关客户端、服务端的概念,然后去把AIDL弄透彻, 知道系统生成的Aidl Java文件中每一个类所代表的是什么角色,然后看源码,能将ActivityManageService 用来跨进程同通信中各个角色弄明白就算是理解了,不过这只是一部分部分,得多总结归纳。

    ActivityThread

    首先ActivityThread并不是一个Thread,其作用就是在main方法内做消息循环。那我们常说的主线程是什么?主线程就是承载ActivityThreadZygote fork而创建的进程 ,这里可能有人会不能理解进程和线程的区别,这里不详细讲述自行学习。ActivityThread的调用是在ActivityManageService.startProcessLocked()方法里调用并创建,这个类主要做了这几个事

    1. 创建Looper,开启Looper循环
    2. 创建内部类 H,H继承于Handler 用于跨进程通信切换线程
    3. 创建ApplicationThread跨进程Binder对象mAppThread。 这里要说一点,ActivityThread通过ApplicationThread与AMS进行通信,ApplicationThread通过H与ActivityThread进行通信(handler机制),处理Activity的事务

    启动方式
    app的启动我们将其分为两种:

    1. 冷启动:当应用启动的时候,后台没有当前应用的进程,这时系统会创建一个新的进程分配给应用。
    2. 热启动:当前应用已经打开,但是被按下返回键或者Home键退出到桌面或者去到其他App,当再次回到应用时就是热启动。
      这里我们主要介绍冷启动过程,首先简单介绍下冷启动的的整个流程,然后再根据关键代码讲解。

    App启动5步走

    借用GITYUAN大神的一张图结合启动App逻辑讲一下App启动的整个流程,不过这是一张Launcher App启动的图,和我们要说的有点不一样,我们根据老罗所说的将App启动分为5步

    1. Launcher通过Binder进程间通信机制通知ActivityManagerService,
      它要启动一个Activity;
    2. ActivityManagerService通过Binder进程间通信机制通知Launcher进入Paused状态;
    3. Launcher通过Binder进程间通信机制通知ActivityManagerService,它已经准备就绪进入Paused状态, 于是ActivityManagerServicey利用Zygote.fork()创建一个新的进程,用来启动一个ActivityThread实例, 即将要启动的Activity就是在这个ActivityThread实例中运行;
    4. ActivityThread通过Binder进程间通信机制将一个ApplicationThread类型的Binder对象传递给ActivityManagerService,
      以便以后ActivityManagerService能够通过这个Binder对象和它进行通信;
    5. ActivityManagerService通过Binder进程间通信机制通知ActivityThread,
      现在一切准备就绪,它可以真正执行Activity的启动操作了。

    在这里插入图片描述

    第一步1-3

    Launcher的点击监听
    首先我们在物理上点击了手机屏幕上的App快捷键图标,这里Launcher是这么操作的呢?我看位于android.launcher2下的源码Launcher

    1、 这里可以看到,Launcher继承于Activity,并在其onClick()事件中监听了app的图标点击,调用了Launcher的startActivitySafely()方法

    
    public final class Launcher extends Activity
            implements View.OnClickListener, OnLongClickListener, LauncherModel.Callbacks, AllAppsView.Watcher {
    ...
    
     /**
         * Launches the intent referred by the clicked shortcut.
         *
         * @param v The view representing the clicked shortcut.
         */
        public void onClick(View v) {
            Object tag = v.getTag();
            if (tag instanceof ShortcutInfo) {
                // Open shortcut
                final Intent intent = ((ShortcutInfo) tag).intent;
                int[] pos = new int[2];
                v.getLocationOnScreen(pos);
                intent.setSourceBounds(new Rect(pos[0], pos[1],
                        pos[0] + v.getWidth(), pos[1] + v.getHeight()));
                startActivitySafely(intent, tag);
            } else if (tag instanceof FolderInfo) {
                handleFolderClick((FolderInfo) tag);
            } else if (v == mHandleView) {
                if (isAllAppsVisible()) {
                    closeAllApps(true);
                } else {
                    showAllApps(true);
                }
            }
        }
    ...
    
    }
    
    

    2、这里将这个启动方式使用Intent.FLAG_ACTIVITY_NEW_TASK, 创建了一个新的TASK栈,然后继续调用父类ActivitystartActivity()方法

     void startActivitySafely(Intent intent, Object tag) {
            intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
            try {
                startActivity(intent);
            } catch (ActivityNotFoundException e) {
                Toast.makeText(this, R.string.activity_not_found, Toast.LENGTH_SHORT).show();
                Log.e(TAG, "Unable to launch. tag=" + tag + " intent=" + intent, e);
            } catch (SecurityException e) {
                Toast.makeText(this, R.string.activity_not_found, Toast.LENGTH_SHORT).show();
                Log.e(TAG, "Launcher does not have the permission to launch " + intent +
                        ". Make sure to create a MAIN intent-filter for the corresponding activity " +
                        "or use the exported attribute for this activity. "
                        + "tag="+ tag + " intent=" + intent, e);
            }
        }
    

    3、Activity的startActivity()方法中传递了默认为-1requestCode,表示不需要返回值,然后调用了startActivityForResult(),在这个方法中我们看到一个mInstrumentation变量,这个变量是Instrumentation对象的实例,具体是在Activity的attach()方法中进行赋值的。然后startActivityForResult()方法中调用了mInstrumentation.execStartActivity()方法,然后在其中传递了两个参数我们要介绍下,

    • mMainThread.getApplicationThread():mMainThread变量声明是 ActivityThread对象,而getApplicationThread()方法则返回的是ApplicationThread的实例。
    • mToken :的声明为 private IBinder mToken;
      这里为什么传递这两个参数我们后面说,我们继续看execStartActivity()方法。
     @Override
        public void startActivity(Intent intent) {
            startActivityForResult(intent, -1);
        }
    
    public void startActivityForResult(Intent intent, int requestCode) {
            if (mParent == null) {
                Instrumentation.ActivityResult ar =
                    mInstrumentation.execStartActivity(
                        this, mMainThread.getApplicationThread(), mToken, this,
                        intent, requestCode);
                if (ar != null) {
                    mMainThread.sendActivityResult(
                        mToken, mEmbeddedID, requestCode, ar.getResultCode(),
                        ar.getResultData());
                }
                if (requestCode >= 0) {
                    // If this start is requesting a result, we can avoid making
                    // the activity visible until the result is received.  Setting
                    // this code during onCreate(Bundle savedInstanceState) or onResume() will keep the
                    // activity hidden during this time, to avoid flickering.
                    // This can only be done when a result is requested because
                    // that guarantees we will get information back when the
                    // activity is finished, no matter what happens to it.
                    mStartedActivity = true;
                }
            } else {
                mParent.startActivityFromChild(this, intent, requestCode);
            }
        }
    

    第二步4-7

    4、我们继续看位于android/app/Instrumentation.java中的execStartActivity方法,最后调用了ActivityManagerNative.getDefault().startActivity()方法,就要和AMS进行Binder的ICP通信了,AMS会收到startActivity的请求,执行startActivity()方法。

    public ActivityResult execStartActivity(Context who, IBinder contextThread, IBinder token, Activity target,
            Intent intent, int requestCode) {
          IApplicationThread whoThread = (IApplicationThread) contextThread;
          if (mActivityMonitors != null) {
            synchronized (mSync) {
                final int N = mActivityMonitors.size();
                for (int i = 0; i < N; i++) {
                    final ActivityMonitor am = mActivityMonitors.get(i);
                    if (am.match(who, null, intent)) {
                        am.mHits++;
                        if (am.isBlocking()) {
                            return requestCode >= 0 ? am.getResult() : null;
                        }
                        break;
                    }
                }
            }
        }
        try {
            int result = ActivityManagerNative.getDefault().startActivity(whoThread, intent,
                intent.resolveTypeIfNeeded(who.getContentResolver()), null, 0, token,
                target != null ? target.mEmbeddedID : null, requestCode, false, false);
            checkStartActivityResult(result, intent);
    } catch (RemoteException e) {
    }
    return null;
    }
    

    5、首先我们知道Launcher本来就是一个Activity,并单独处于一个进程中,现在要启动另一个我们所点击的APP的Activity,而AMS是管理所有Activity的,那么我们就会和AMS使用Binder进行跨进程通信。
    这里我们也具体了解下是谁和AMS进行跨进程通信?
    使用Binder进行通信,就首先得有Server进程和Client进程,
    首先Server会提供一套接口函数供Client调用,这个时候通常会采用Proxy设计模式。将接口定义在一个抽象类中,Server和Client都会以该抽象类为基础实现所有函数。 而在Client端会具有Server端的代理对象Proxy,Proxy具有和Server一样的方法,Client使用代理对象经过Binder的转换,跨进程调用Server的服务。具体理解这一块先看看AIDl相关。

    再回到步骤4 的ActivityManagerNative.getDefault().startActivity()方法,这个方法后面调用asInterface()然后返回ActivityManagerProxy对象,这个对象其实就是AMS在客户端的代理对象,ActivityManagerProxy实现IActivityManager接口,具有AMS所提供的方法,不同的是,ActivityManagerProxy并没有实现方法,ActivityManagerProxy只是将客服端发起的请求进行参数进行打包封装,并在每一个方法中添加唯一表示,然后将请求发送到Binder,Binder就会将请求转发给server,server根据唯一表示调用相应的server的相关方法
    再看下AMS:AMS继承了ActivityManagerNative同样实现了IActivityManager接口。这里就能

    也就是说与AMS通信的其实是AMS的代理对象ActivityManagerProxy,通过:ActivityManagerProxy -> Binder驱动 -> AMS

    public final class ActivityManagerService extends ActivityManagerNative implements Watchdog.Monitor {}
    
    public abstract class ActivityManagerNative extends Binder implements IActivityManager{}
    
    class ActivityManagerProxy implements IActivityManager{}
    
    
    private final class ApplicationThread extends ApplicationThreadNative {}
    
    public abstract class ActivityManagerNative extends Binder implements IActivityManager{
    。。。
     static public IActivityManager getDefault()
        {
          ...
            IBinder b = ServiceManager.getService("activity");
            if (Config.LOGV) Log.v(
                "ActivityManager", "default service binder = " + b);
            gDefault = asInterface(b);
          ...
            return gDefault;
        }
    
    
     static public IActivityManager asInterface(IBinder obj)
        {
            if (obj == null) {
                return null;
            }
            IActivityManager in =
                (IActivityManager)obj.queryLocalInterface(descriptor);
            if (in != null) {
                return in;
            }
            
            return new ActivityManagerProxy(obj);
        }
    
    class ActivityManagerProxy implements IActivityManager{}
    ...
    }
    

    在这里插入图片描述

    6、Activity通过Binder将消息传递到了AMS,AMS的startActivity()方法接收到方法开始一系列的调用,这里整个AMS会做几个操作

    1. 对参数intent的内容进行解析,保存到ResolveInfo对象中
    2. 从传进来的参数得到调用者的进程信息,保存到ProcessRcord对象中,这里获取的就是Launcher应用程序的进程
    3. 创建即将要启动的Activity的相关信息 保存到ActivityRecord对象
    4. 根据intent的参数设置启动模式,并创建一个新的Task来启动这个Activity
    5. 将创建的Task保存到ActivityManagerService
    6. 将Launcher推入Paused状态
    public final class ActivityManagerService extends ActivityManagerNative implements Watchdog.Monitor {
    
    ...
    
    	public final int startActivity(IApplicationThread caller,
                Intent intent, String resolvedType, Uri[] grantedUriPermissions,
                int grantedMode, IBinder resultTo,
                String resultWho, int requestCode, boolean onlyIfNeeded,
                boolean debug) {
            return startActivityMayWait(caller, intent, resolvedType,
                    grantedUriPermissions, grantedMode, resultTo, resultWho,
                    requestCode, onlyIfNeeded, debug, null, null);
        }
    
    
     private final int startActivityMayWait(IApplicationThread caller,
                Intent intent, String resolvedType, Uri[] grantedUriPermissions,
                int grantedMode, IBinder resultTo,
                String resultWho, int requestCode, boolean onlyIfNeeded,
                boolean debug, WaitResult outResult, Configuration config) {
    ...
      int res = startActivityLocked(caller, intent, resolvedType,
                        grantedUriPermissions, grantedMode, aInfo,
                        resultTo, resultWho, requestCode, callingPid, callingUid,
                        onlyIfNeeded, componentSpecified);
    ...
    }
    
    // 调用到startActivityUncheckedLocked的时候就说明要启动的Activity已经通过检查,被认为是一个正当的启动请求
     private final int startActivityLocked(IApplicationThread caller,
                Intent intent, String resolvedType,
                Uri[] grantedUriPermissions,
                int grantedMode, ActivityInfo aInfo, IBinder resultTo,
                String resultWho, int requestCode,
                int callingPid, int callingUid, boolean onlyIfNeeded,
                boolean componentSpecified) {
    
      return startActivityUncheckedLocked(r, sourceRecord,
                    grantedUriPermissions, grantedMode, onlyIfNeeded, true);
    }
    
    private final int startActivityUncheckedLocked(HistoryRecord r,
                HistoryRecord sourceRecord, Uri[] grantedUriPermissions,
                int grantedMode, boolean onlyIfNeeded, boolean doResume) {
    ...
      startActivityLocked(r, newTask, doResume);
            return START_SUCCESS;
    ...
    }
    
    //
     private final void startActivityLocked(HistoryRecord r, boolean newTask,
                boolean doResume) {
    ...
    if (doResume) {
                resumeTopActivityLocked(null);
            }
    ...
    }
    
    //
     private final boolean resumeTopActivityLocked(HistoryRecord prev) {
    ...
    if (mResumedActivity != null) {
                if (DEBUG_SWITCH) Slog.v(TAG, "Skip resume: need to start pausing");
                startPausingLocked(userLeaving, false);
                return true;
            }
    ...
    }
    

    7、AMS处理完Activity相关设置后,调用prev.app.thread.schedulePauseActivity()方法, 这里的prev.app.thread是一个ApplicationThread对象的远程接口,通过调用这个远程接口的schedulePauseActivity来通知Launcher进入Paused状态。schedulePauseActivity方法定义在 IApplicationThread.java 文件中
    到这里,AMS通知Launcher要启动一个Activity,Launcher也要进入到Paused了,后面也会用到我们第3步中的token。

     private final void startPausingLocked(boolean userLeaving, boolean uiSleeping) {
    ...
       if (prev.app != null && prev.app.thread != null) {
                if (DEBUG_PAUSE) Slog.v(TAG, "Enqueueing pending pause: " + prev);
                try {
                    EventLog.writeEvent(EventLogTags.AM_PAUSE_ACTIVITY,
                            System.identityHashCode(prev),
                            prev.shortComponentName);
                    prev.app.thread.schedulePauseActivity(prev, prev.finishing, userLeaving,
                            prev.configChangeFlags);
                    updateUsageStats(prev, false);
                } catch (Exception e) {
                    // Ignore exception, if process died other code will cleanup.
                    Slog.w(TAG, "Exception thrown during pause", e);
                    mPausingActivity = null;
                    mLastPausedActivity = null;
                }
            } else {
                mPausingActivity = null;
                mLastPausedActivity = null;
            }
    
    ...
    }
    ...
    
    }
    

    第三步 8-12

    8、这里AMS又要通过Binder通知Launcher更新状态(这里要知道AMS是和ActivityThread进行通信),而AMS 是这么和 ActivityThread进行跨进程通信? 看了上面的第5步,我们知道跨进程通信总得实现同一个接口,我们再归纳下AMS和ActivityThread的进行跨进程通信。

    之前我们说到ActivityThread是通过ApplicationThread与AMS进行通信的,ApplicationThread也是继承ApplicationThreadNative实现了同样的IActivityManager接口。ApplicationThreadProxy也是实现了IApplicationThread接口。
    也就是说与和AMS通信是:ApplicationThreadProxy -> Binder驱动 -> ApplicationThread。

     private final class ApplicationThread extends ApplicationThreadNative {}
    
    public abstract class ApplicationThreadNative extends Binder
            implements IApplicationThread {}
    
    class ApplicationThreadProxy implements IApplicationThread {}
    
    

    9、我们继续步骤7中最后调用的schedulePauseActivity()方法,这个函数通过Binder进程间通信机制进入到ApplicationThread.schedulePauseActivity函数中

    class ApplicationThreadProxy implements IApplicationThread {
    ...
    public final void schedulePauseActivity(IBinder token, boolean finished,
                boolean userLeaving, int configChanges) throws RemoteException {
            Parcel data = Parcel.obtain();
            data.writeInterfaceToken(IApplicationThread.descriptor);
            data.writeStrongBinder(token);
            data.writeInt(finished ? 1 : 0);
            data.writeInt(userLeaving ? 1 :0);
            data.writeInt(configChanges);
            mRemote.transact(SCHEDULE_PAUSE_ACTIVITY_TRANSACTION, data, null,
                    IBinder.FLAG_ONEWAY);
            data.recycle();
        }
    ...
    }
    
    //当 finished 为false 时候,queueOrSendMessage的第一个参数值为H.PAUSE_ACTIVITY,表示要暂停token所代表的Activity,即Launcher,也就是第3步传过来的mToken实例
    private final class ApplicationThread extends ApplicationThreadNative {
    ...
     public final void schedulePauseActivity(IBinder token, boolean finished,
                    boolean userLeaving, int configChanges) {
                queueOrSendMessage(
                        finished ? H.PAUSE_ACTIVITY_FINISHING : H.PAUSE_ACTIVITY,
                        token,
                        (userLeaving ? 1 : 0),
                        configChanges);
            }
    ...
    }
    

    10、我们继续看queueOrSendMessage()方法,在方法看到 mH.sendMessage(msg),这个mH就是Activity中的继承于Hander的内部类H,根据handler我知道有发送就有接收,并且我们知道发送的what是H.PAUSE_ACTIVITY。

     private final void queueOrSendMessage(int what, Object obj, int arg1, int arg2) {
            synchronized (this) {
                if (localLOGV) Slog.v(
                    TAG, "SCHEDULE " + what + " " + mH.codeToString(what)
                    + ": " + arg1 + " / " + obj);
                Message msg = Message.obtain();
                msg.what = what;
                msg.obj = obj;
                msg.arg1 = arg1;
                msg.arg2 = arg2;
                mH.sendMessage(msg);
            }
        }
    

    11、继续看handler接收,在接收的地方调用了handlePauseActivity()方法,将binder引用token转换成ActivityRecord,然后做了三个事情:

    1. 如果userLeaving为true,则通过调用performUserLeavingActivity函数来调用Activity.onUserLeaveHint通知Activity,用户要离开它了;
    2. 调用performPauseActivity函数来调用Activity.onPause函数,我们知道,在Activity的生命周期中,当它要让位于其它的Activity时,系统就会调用它的onPause函数;
    3. 它通知ActivityManagerService,这个Activity已经进入Paused状态了,ActivityManagerService现在可以完成未竟的事情,即启动MainActivity了。
     private final class H extends Handler {
    ...
    
    	public void handleMessage(Message msg) {
     	 switch (msg.what) {
     	case PAUSE_ACTIVITY:
                        handlePauseActivity((IBinder)msg.obj, false, 			    msg.arg1 != 0, msg.arg2);
                        maybeSnapshot();
                        break;
    }
    ...
    }
    
    
     private final void handlePauseActivity(IBinder token, boolean finished,
                boolean userLeaving, int configChanges) {
            ActivityRecord r = mActivities.get(token);
            if (r != null) {
                //Slog.v(TAG, "userLeaving=" + userLeaving + " handling pause of " + r);
                if (userLeaving) {
                    performUserLeavingActivity(r);
                }
    
                r.activity.mConfigChangeFlags |= configChanges;
                Bundle state = performPauseActivity(token, finished, true);
    
                // Tell the activity manager we have paused.
                try {
                    ActivityManagerNative.getDefault().activityPaused(token, state);
                } catch (RemoteException ex) {
                }
            }
        }
    
    
     final Bundle performPauseActivity(ActivityRecord r, boolean finished,
                boolean saveState) {
    ...
    	// 调用 onPause();
    	mInstrumentation.callActivityOnPause(r.activity);
    ...
    }
    

    12、继续看通过Binder机制调用AMS的方法, 看这个方法 ActivityManagerNative.getDefault().activityPaused(token, state)是不是感觉很熟悉了;这又是一次跨进程通信,这个方法首先会调用ActivityManagerProxy 相应的方法,然后跨进程传递到ActivityManagerService的activityPaused()方法执行,然后一路向下调用。

    class ActivityManagerProxy implements IActivityManager{
    ...
    	public void activityPaused(IBinder token, Bundle state) throws RemoteException
        {
            Parcel data = Parcel.obtain();
            Parcel reply = Parcel.obtain();
            data.writeInterfaceToken(IActivityManager.descriptor);
            data.writeStrongBinder(token);
            data.writeBundle(state);
            mRemote.transact(ACTIVITY_PAUSED_TRANSACTION, data, reply, 0);
            reply.readException();
            data.recycle();
            reply.recycle();
        }
    ...
    }
    
    public final class ActivityManagerService extends ActivityManagerNative implements Watchdog.Monitor {           
    ...
    	public final void activityPaused(IBinder token, Bundle icicle) {
            // Refuse possible leaked file descriptors
            if (icicle != null && icicle.hasFileDescriptors()) {
                throw new IllegalArgumentException("File descriptors passed in Bundle");
            }
    
            final long origId = Binder.clearCallingIdentity();
            activityPaused(token, icicle, false);
            Binder.restoreCallingIdentity(origId);
        }
    ...
    }
    
    final void activityPaused(IBinder token, Bundle icicle, boolean timeout) {
    ...
     	synchronized (this) {
              ...
                        completePauseLocked();
              ...
            }
    ...
    }
    
    
    
    private final void completePauseLocked() {
    ...
    	if (!mSleeping && !mShuttingDown) {
                resumeTopActivityLocked(prev);
            } else {
            }
    ...
    }
    
    
    private final boolean resumeTopActivityLocked(HistoryRecord prev) {
    ...
     	startSpecificActivityLocked(next, true, true);
    ...
    }
    
    
    private final void startSpecificActivityLocked(HistoryRecord r,
                boolean andResume, boolean checkConfig) {
    ...
    	startProcessLocked(r.processName, r.info.applicationInfo, true, 0,
                    "activity", r.intent.getComponent(), false);
    ...
    }
    
    

    主要是调用Process.start接口来创建一个新的进程,新的进程会导入android.app.ActivityThread类,并且执行它的main函数,其中会根据uid+process的组合为应用创建一个ProcessRecord,并验证是否有process + uid命名的进程存在

    private final void startProcessLocked(ProcessRecord app,
                String hostingType, String hostingNameStr) {
    ...
    	int pid = Process.start("android.app.ActivityThread",
                        mSimpleProcessManagement ? app.processName : null, uid, uid,
                        gids, debugFlags, null);
    ...
    }
    

    第四步 13-14

    13、现在AMS创建了一个进程ActivityThread,并启动这个类的main方法,先是创建一个Looper,然后调用thread.attach()方法,后面开始消息循环直到进程退出,然后一直到ActivityManageProxy的相应方法,然后通过Binder 机制向ActivityManagerService传递了一个ApplicationThread类型的Binder对象,作用是用于进程间通信。通信方式就是过程8所介绍的

    public final class ActivityThread {
    ...
    public static final void main(String[] args) {
    ...
    	Looper.prepareMainLooper();
            ActivityThread thread = new ActivityThread();
            thread.attach(false);
            Looper.loop();
    ...
    }
    
     private final void attach(boolean system) {
     	IActivityManager mgr = ActivityManagerNative.getDefault();
                try {
                    mgr.attachApplication(mAppThread);
                } catch (RemoteException ex) {
                }
    }
    ...
    }
    
    
    class ActivityManagerProxy implements IActivityManager{
    ...
     public void attachApplication(IApplicationThread app) throws RemoteException
        {
            Parcel data = Parcel.obtain();
            Parcel reply = Parcel.obtain();
            data.writeInterfaceToken(IActivityManager.descriptor);
            data.writeStrongBinder(app.asBinder());
            mRemote.transact(ATTACH_APPLICATION_TRANSACTION, data, reply, 0);
            reply.readException();
            data.recycle();
            reply.recycle();
        }
    ...
    }
    

    14、ActivityThread使用调用attachApplication()方法使用Binder机制向AMS传递了一个Application对象,AMS的接受到后调用相应的attachApplication()方法

    public final class ActivityManagerService extends ActivityManagerNative implements Watchdog.Monitor {
    ...
     public final void attachApplication(IApplicationThread thread) {
            synchronized (this) {
                int callingPid = Binder.getCallingPid();
                final long origId = Binder.clearCallingIdentity();
                attachApplicationLocked(thread, callingPid);
                Binder.restoreCallingIdentity(origId);
            }
        }
    ...
    }
    
     private final boolean attachApplicationLocked(IApplicationThread thread,
                int pid) {
    ...
    
    	try {
    		if (realStartActivityLocked(hr, app, true, true)) {
                            didSomething = true;
                        }
                    } catch (Exception e) {
                      
                    }
    ...
    }
    
    
    //最终通过app.thread进入到ApplicationThreadProxy的scheduleLaunchActivity函数中
    private final boolean realStartActivityLocked(HistoryRecord r,
                ProcessRecord app, boolean andResume, boolean checkConfig)
                throws RemoteException {
    ...
     app.thread.scheduleLaunchActivity(new Intent(r.intent), r,
                        System.identityHashCode(r),
                        r.info, r.icicle, results, newIntents, !andResume,
                        isNextTransitionForward());
    
    ...
    }
    

    第五步15

    15、AMS得到了ActivityThread的Application对象后,又个给ActivityThread发送了一个消息,调用了ApplicationThread的scheduleLaunchActivity()方法,这里我们一定要将前面讲的:AMS和ActivityThread通过ApplicationThread通信弄明白

    class ApplicationThreadProxy implements IApplicationThread {
    ...
    public final void scheduleLaunchActivity(Intent intent, IBinder token, int ident,
                ActivityInfo info, Bundle state, List<ResultInfo> pendingResults,
        List<Intent> pendingNewIntents, boolean notResumed, boolean isForward)
        throws RemoteException {
            Parcel data = Parcel.obtain();
            data.writeInterfaceToken(IApplicationThread.descriptor);
            intent.writeToParcel(data, 0);
            data.writeStrongBinder(token);
            data.writeInt(ident);
            info.writeToParcel(data, 0);
            data.writeBundle(state);
            data.writeTypedList(pendingResults);
            data.writeTypedList(pendingNewIntents);
            data.writeInt(notResumed ? 1 : 0);
            data.writeInt(isForward ? 1 : 0);
            mRemote.transact(SCHEDULE_LAUNCH_ACTIVITY_TRANSACTION, data, null,
                    IBinder.FLAG_ONEWAY);
            data.recycle();
        }
    
    ...
    }
    

    //然后调用到ApplicationThread的相应方法,创建一个ActivityRecord实例,并且初始化它的成员变量,然后调用ActivityThread类的queueOrSendMessage函数进一步处理。

     private final class ApplicationThread extends ApplicationThreadNative {
    ...
    public final void scheduleLaunchActivity(Intent intent, IBinder token, int ident,
                    ActivityInfo info, Bundle state, List<ResultInfo> pendingResults,
                    List<Intent> pendingNewIntents, boolean notResumed, boolean isForward) {
                ActivityRecord r = new ActivityRecord();
              r.token = token;
                r.ident = ident;
                r.intent = intent;
                r.activityInfo = info;
                r.state = state;
    
                r.pendingResults = pendingResults;
                r.pendingIntents = pendingNewIntents;
    
                r.startsNotResumed = notResumed;
                r.isForward = isForward;
                queueOrSendMessage(H.LAUNCH_ACTIVITY, r);
            }
    ...
    }
    

    我们之前说过,进程内存是使用Handler进行线程间调用,这里ActivityThread和ApplicationThread就是使用小H类 Handler发送了一个what为 H.LAUNCH_ACTIVITY的消息,我们再看接收的地方

     private final void queueOrSendMessage(int what, Object obj, int arg1, int arg2) {
            synchronized (this) {
                if (localLOGV) Slog.v(
                    TAG, "SCHEDULE " + what + " " + mH.codeToString(what)
                    + ": " + arg1 + " / " + obj);
                Message msg = Message.obtain();
                msg.what = what;
                msg.obj = obj;
                msg.arg1 = arg1;
                msg.arg2 = arg2;
                mH.sendMessage(msg);
            }
        }
    
    

    // 这里首先调用performLaunchActivity函数来加载这个Activity类,即 MainActivity,然后调用它的onCreate函数。再调用handleResumeActivity函数来使这个Activity进入Resumed状态,即会调用这个Activity的onResume函数,这是遵循Activity的生命周期的。

     private final class H extends Handler {
    ...
     public void handleMessage(Message msg) {
     switch (msg.what) {
                    case LAUNCH_ACTIVITY: {
                        ActivityRecord r = (ActivityRecord)msg.obj;
    
                        r.packageInfo = getPackageInfoNoCheck(
                                r.activityInfo.applicationInfo);
                        handleLaunchActivity(r, null);
                    } break;
    }
    }
    ...
    }
    
     private final void handleLaunchActivity(ActivityRecord r, Intent customIntent) {
            // If we are getting ready to gc after going to the background, well
            // we are back active so skip it.
            unscheduleGcIdler();
    
            if (localLOGV) Slog.v(
                TAG, "Handling launch of " + r);
            Activity a = performLaunchActivity(r, customIntent);
    ...
    }
    
    private final Activity performLaunchActivity(ActivityRecord r, Intent customIntent) {
            // System.out.println("##### [" + System.currentTimeMillis() + "] ActivityThread.performLaunchActivity(" + r + ")");
         // 1、 收集要启动的Activity的相关信息,主要package和component信息,
            ActivityInfo aInfo = r.activityInfo;
            if (r.packageInfo == null) {
                r.packageInfo = getPackageInfo(aInfo.applicationInfo,
                        Context.CONTEXT_INCLUDE_CODE);
            }
    
            ComponentName component = r.intent.getComponent();
            if (component == null) {
                component = r.intent.resolveActivity(
                    mInitialApplication.getPackageManager());
                r.intent.setComponent(component);
            }
    
            if (r.activityInfo.targetActivity != null) {
                component = new ComponentName(r.activityInfo.packageName,
                        r.activityInfo.targetActivity);
            }
    
            Activity activity = null;
            try {
    //2、然后通过ClassLoader将shy.luo.activity.MainActivity类加载进来:
                java.lang.ClassLoader cl = r.packageInfo.getClassLoader();
                activity = mInstrumentation.newActivity(
                        cl, component.getClassName(), r.intent);
                r.intent.setExtrasClassLoader(cl);
                if (r.state != null) {
                    r.state.setClassLoader(cl);
                }
            } catch (Exception e) {
                if (!mInstrumentation.onException(activity, e)) {
                    throw new RuntimeException(
                        "Unable to instantiate activity " + component
                        + ": " + e.toString(), e);
                }
            }
    
            try {
    //3、创建Application对象,这是根据AndroidManifest.xml配置文件中的Application标签的信息来创建
                Application app = r.packageInfo.makeApplication(false, mInstrumentation);
    
                if (localLOGV) Slog.v(TAG, "Performing launch of " + r);
                if (localLOGV) Slog.v(
                        TAG, r + ": app=" + app
                        + ", appName=" + app.getPackageName()
                        + ", pkg=" + r.packageInfo.getPackageName()
                        + ", comp=" + r.intent.getComponent().toShortString()
                        + ", dir=" + r.packageInfo.getAppDir());
    
                if (activity != null) {
                    ContextImpl appContext = new ContextImpl();
                    appContext.init(r.packageInfo, r.token, this);
                    appContext.setOuterContext(activity);
                    CharSequence title = r.activityInfo.loadLabel(appContext.getPackageManager());
                    Configuration config = new Configuration(mConfiguration);
                    if (DEBUG_CONFIGURATION) Slog.v(TAG, "Launching activity "
                            + r.activityInfo.name + " with config " + config);
    //4、创建Activity的上下文信息,并通过attach方法将这些上下文信息设置到MainActivity中去
                    activity.attach(appContext, this, getInstrumentation(), r.token,
                            r.ident, app, r.intent, r.activityInfo, title, r.parent,
                            r.embeddedID, r.lastNonConfigurationInstance,
                            r.lastNonConfigurationChildInstances, config);
    
                    if (customIntent != null) {
                        activity.mIntent = customIntent;
                    }
                    r.lastNonConfigurationInstance = null;
                    r.lastNonConfigurationChildInstances = null;
                    activity.mStartedActivity = false;
                    int theme = r.activityInfo.getThemeResource();
                    if (theme != 0) {
                        activity.setTheme(theme);
                    }
    
                    activity.mCalled = false;
    //5、 最后还要调用MainActivity的onCreate函数,这里不是直接调用MainActivity的onCreate函数,而是通过Instrumentation类的callActivityOnCreate函数来间接调用,前面我们说过,mInstrumentation在这里的作用是监控Activity与系统的交互操作,相当于是系统运行日志
                    mInstrumentation.callActivityOnCreate(activity, r.state);
                    if (!activity.mCalled) {
                        throw new SuperNotCalledException(
                            "Activity " + r.intent.getComponent().toShortString() +
                            " did not call through to super.onCreate()");
                    }
                    r.activity = activity;
                    r.stopped = true;
                    if (!r.activity.mFinished) {
                        activity.performStart();
                        r.stopped = false;
                    }
                    if (!r.activity.mFinished) {
                        if (r.state != null) {
                            mInstrumentation.callActivityOnRestoreInstanceState(activity, r.state);
                        }
                    }
                    if (!r.activity.mFinished) {
                        activity.mCalled = false;
                        mInstrumentation.callActivityOnPostCreate(activity, r.state);
                        if (!activity.mCalled) {
                            throw new SuperNotCalledException(
                                "Activity " + r.intent.getComponent().toShortString() +
                                " did not call through to super.onPostCreate()");
                        }
                    }
                }
                r.paused = true;
    
                mActivities.put(r.token, r);
    
            } catch (SuperNotCalledException e) {
                throw e;
    
            } catch (Exception e) {
                if (!mInstrumentation.onException(activity, e)) {
                    throw new RuntimeException(
                        "Unable to start activity " + component
                        + ": " + e.toString(), e);
                }
            }
    
            return activity;
        }
    

    到这里经过一系列的调用和跨进程通信终于启动了Activity

    Android 应用程序启动过程分析

    Android 应用进程启动流程
    Android进程启动流程(App启动)
    Activity启动过程全解析
    Android Launcher 启动 Activity 的工作过程
    Android Application启动流程分析
    Android应用程序启动过程源代码分析
    写给Android App开发人员看的Android底层知识(2)
    从应用角度看Android源码 - 是谁调用的ActivityThread的main方法
    ActivityThread

    展开全文
  • Android App 启动时显示正在加载图片

    热门讨论 2014-07-10 13:05:34
    Android App 启动时显示正在加载图片,如微信,人人,qq,天天动听等
  • 一键跳过 APP 启动广告

    千次阅读 2021-01-27 08:20:00
    之前分享过去网页广告如何去除烦人的垃圾广告,这里再分享下去APP 启动广告,现在的APP启动广告是越来越迷惑了,比如这种提示未发现网络,你点刷新就跳进广告了,真让人防不胜防。一般启动广告是5秒,比如这种,...
  • Android性能优化系列之App启动优化

    万次阅读 多人点赞 2017-02-22 00:23:29
    Android性能优化系列之布局优化Android性能优化系列之内存优化Android性能优化系列之apk瘦身应用的启动速度缓慢是我们在开发过程中经常会遇到的问题,比如启动缓慢导致的...,本篇博客就将介绍App启动优化的相关知识...
  • Android app启动时白屏

    千次阅读 2019-06-24 10:03:29
    我们在打开一个APP时,肯定希望它能够快速响应,然后快速启动。而当我们首次启动APP时,再到APP的第一个页面展示出来之前,这段时间会有几秒的白屏或者是黑屏出现。这样给用户的体验是十分不好的。 之所以会出现这种...
  • APP启动时间优化

    千次阅读 2019-10-23 17:35:17
    一般而言,大家把iOS冷启动的过程定义为:从用户点击App图标开始到appDelegate didFinishLaunching方法执行完成为止。这个过程主要分为两个阶段: T1:main()函数之前,即操作系统加载App可执行文件到内存,然后...
  • Android面试题(31)-App启动流程

    千次阅读 多人点赞 2018-03-08 23:43:59
    在看这篇文章之前,希望先看完我的之前的博客 android面试(6)-Binder机制,因为关于App启动流程设计很多Binder通信; 先将“三个进程”,“六个大类”进行介绍: 三个进程: Launcher进程:整个App启动流程的...
  • 如何测试app启动时间?

    千次阅读 2018-04-01 19:12:41
     2)首次/非首次启动应用,进入应用特别慢——应用启动慢; 3)应用使用过程中,越来越卡——CPU能力不足/内存泄露; 4)应用页面卡顿——帧率较低、页面卡顿。 因此,对开发的Android应用,必须对其进行性能测试...
  • 如何Hook app启动阶段的方法onCreate 启动阶段即app没有完全启动起来。 正常在hook一个app之前,要将app运行起来才可以进行hook,但是有些时候我们hook的方法是在app启动阶段执行的,该方法在启动阶段执行一次之后在...
  • App 启动时间优化方法详解

    千次阅读 2017-11-24 15:53:31
    本文将讨论如何优化应用的启动时间,首先我们需要了解app启动的相关内容。 App 启动模式分类 应用中冷启动避免白屏、黑屏方案 Framework 层解决冷启动白屏、黑屏方案 App 启动优化原理 App 启动优化简介 Ap.....
  • Android 解决APP启动时出现白屏问题

    万次阅读 2018-07-24 16:49:01
    当我们首次启动APP时,再到APP的第一个页面展示出来之前,这段时间会有几秒的白屏或者是黑屏出现。这样给用户的体验是十分不好的。 2、问题出现的原因: 当我们在启动一个应用时,系统会检查是否已经存在这样一个...
  • 上一篇App启动已经初步的分析了有哪些启动类型以及怎么去简单的测量App启动的耗时,这一篇主要使用两个工具来粗略的分析启动的耗时到底在哪些地方。下面开始介绍 1 使用systrace抓取trace.html文件 在使用Systrace...
  • Android&IOS APP启动速度专项测试方法

    千次阅读 2020-12-16 17:09:21
    APP启动速度是一个APP体验好坏最重要的一个标志,一般APP上线之前都会进行启动速度的专项测试,最近看了很多这个测试方法,发现大家说的都不一致,我在这里总结下,用下面这个方法测试出来的启动速度是比较贴合用户...
  • uni-app设置APP启动页显示时长

    千次阅读 2020-08-17 15:20:38
    最近在使用uni-app开发APP,发现打开APP后启动页总是一闪而过(因为首页已经渲染完成,会自动从启动页跳转到首页),很显然这不符合...首先在manifest.json的App启动界面配置中取消勾选“等待首页渲染完毕后再关闭Splas
  • App 启动时间过长,该怎样优化

    千次阅读 2019-09-27 18:54:40
    App 启动时间过长,可能有多个原因造成的,从理论上说App启动时间是由mian()函数之前的加载时间(t1)和mian函数之后的加载时间(t2)组成的 关于t1 需要分析App 启动日志,具体方法是在Xcode 添加 DYLD_PRINT_...
  • 一、应用的启动方式及过程: 应用的启动分为冷启动、热启动、温启动,其中冷启动是最慢的。 以下是应用冷启动的启动过程: 加载启动App;...当在App启动之后立即展示出一个空白页,这个空白大...
  • Android APP启动图标尺寸

    千次阅读 2020-05-09 14:33:45
    注,小米图标圆角要求: 7201280 px的安卓设计界面 对应的启动图标尺寸是 96px96px 圆角约等于18px 1080*1920px的安卓界面设计 对应的启动图标尺寸是144px 144px 圆角约等于25px 二、Android 8.0以后图标的规范 在 ...
  • App 启动时间优化方法详解 ...本文将讨论如何优化应用的启动时间,首先我们需要了解app启动的相关内容。 App 启动模式分类 应用中冷启动避免白屏、黑屏方案 Framework 层解决冷启动白屏、黑屏方案 App 启动优...
  • Android性能调优:App启动速度优化

    千次阅读 2019-07-11 15:51:36
    一、App启动分类 1.冷启动 Cold start 在启动应用前,系统还没有App的任何进程。比如设备开机后应用的第一次启动,系统杀掉应用进程 (如:系统内存吃紧引发的 kill 和 用户主动产生的 kill) 后 的再次启动等。那么...
  • APP启动黑屏白屏原因与解决方式

    千次阅读 2020-03-29 17:10:58
    我们在桌面启动自己辛苦创建的APP时,总是会看到黑屏或是白屏现象,这让人的体验感觉不是很好,看看大厂的APP为什么不会有这个现象?有问题就要解决,即便不是BUG,用户体验一样很重要。
  • App启动图片变形,拉伸

    千次阅读 2020-01-08 14:44:31
    Hbuilderx开发App上传启动图片变形,拉伸 解决: 使用.9.png图,俗称(9妹图) 注:9妹图以 .9.png 为后缀 制作9妹图: 安装Android SDK 打开 android-sdk\tools\draw9patch.bat 紫色为拉伸区域 ...
  • 一、启动原理解析 Android是基于Linux内核的,当手机启动,加载完Linux内核后,会由Linux系统的init祖先进程fork出Zygote进程,所有的Android应用程序进程以及系统服务进程都是这个Zygote的子进程(由它fork出来的)...
  • 本文以图文并茂的形式简单介绍一个APP启动到主页面显示经历了哪些流程,以及实现的原理。不介绍具体源码,仅仅构建一个大体框架。原地址链接:http://www.jianshu.com/p/a72c5ccbd150一、流程概述启动流程:①点击...
  • uni-app启动时间太长

    千次阅读 2020-11-01 15:29:38
    uni-app启动时间太长编译微信小程序时间过长的解决办法 打开manifest.json,作如下配置就可以了,可以瞬间启动! 详细步骤: 1.打开manifest.json; 2.点击“APP启动图配置”选项; 3.把启动界面选项的前两项...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 837,961
精华内容 335,184
关键字:

app启动