app 启动流程

为了写这篇文章,我可是找了好些资料,看了好几天才把其中关节顺下来好清楚,资料很多,有说 app 冷启动的,有说从 Activity 启动 Activity 的,还有说 window 加载页面的,这些其实都时勾着的,一环套一环,区别是有的时候有些环节不会跑。这里我从头带大家走一下,整个顺一遍下来就都清楚了

app 冷启动是说从桌面启动 app ,此时我们的应用是没有进程的,需要创建。Activity 启动 Activity,指的是进程内启动新的页面,此时应用进程是存在的。系统桌面也是一个 Activity ,名叫 Launch ,所以 app 冷启动和 Activity 启动 Activity 差不多,走的都是 Activity 内部的方法,区别就是先启动应用进程的事,这样说大家就对这两种启动 Activity 的情况心里有数了

这块必须清楚,因为面试时很多时候会问的,有的面试官会问你2者的关联,区别,简单的自会问你 Activity 启动流程,你把2种 Activity 启动方式的关联一说,绝对涨分。除了面试环节外,我们也能熟悉下系统流程,后面插件化会用到,另外也会对我们自己封装框架,学习系统其他深入知识点有很大的帮助,比如 AIDL 双向通讯,功能分割,代理分层,有助于我们以后看各种框架

app 的启动流程简单来说:

  1. 用户点击 icon
  2. 系统开始加载和启动应用
  3. 应用启动:开启空白(黑色)窗口
  4. 创建应用进程
  5. 初始化Application
  6. 启动 UI 线程
  7. 创建第一个 Activity
  8. 解析(Inflater)和加载内容视图
  9. 布局(Layout)
  10. 绘制(Draw)

涉及系统类如下:

  • Application
  • Activity
    • Instrumentation
      • H
    • ActivityThread
      • IApplicationThread
  • ActivityManagerService
    • IActivityManager
  • window
    • ViewRootImpl
  1. 一对 AIDL 双向通讯
    IApplicationThread 和 IActivityManager 是一对配套的 AIDL 接口
  • IActivityManager 负责 Activity -> ActivityManagerService 的通讯
  • IApplicationThread 负责 ActivityManagerService -> Activity 的通讯
  • 双向通讯的绑定是在 Activity 拿到同 ActivityManagerService 通讯的 AIDL 时把自己的 IApplicationThread 也就是反向 AIDL 接口交给 ActivityManagerService ,这样2者形成 AIDL 双向通讯
  1. 功能分层,代码类聚

若是按照 MVP 的思路来说:

  • V 层是 widow ,负责 Activity 界面的渲染
  • P 层是 Instrumentation,封装了 Activity 所有的操作逻辑,所有的操作逻辑入口都是在 Instrumentation 里面
  • M 层是 ActivityThread ,ActivityThread 持有 Activity 和远程操作的 AIDL 交互接口

这么看的话,Activity 要清晰很多了,限于我小白的水平,估计有一些写的不全,分析的疏漏的地方大家见谅呀~


正式开始

找到还可以的流程图,方便后面比对


1. startActivity 我们去启动一个新页面

平时我们自己启动 Activity 都是用的 startActivity 这个方法,那么对于 app 冷启动,LaunchActivity 是怎么跑的?

看代码,LaunchActivity 也没多干什么事,LaunchActivity 会解析我们点击图标对应的 app 的配置文件,获取期中信息构建 intent ,然后再调用 startActivity

        // 桌面点击app图标
        public void onClick(View v) {
            ...
            Object tag = v . getTag ();
            if (tag instanceof ShortcutInfo) {
                onClickAppShortcut(v);
            }
        }

        protected void onClickAppShortcut(final View v) {
            ...
            // Start activities
            startAppShortcutOrInfoActivity(v);
        }

        private void startAppShortcutOrInfoActivity(View v) {
            ItemInfo item =(ItemInfo) v . getTag ();
            Intent intent;
            // 通过 PackageManagerService 解析 AndroidManifest.xml 
            if (item instanceof PromiseAppInfo) {
                PromiseAppInfo promiseAppInfo =(PromiseAppInfo) item;
                intent = promiseAppInfo.getMarketIntent();
            } else {
                intent = item.getIntent();
            }
            ...
            boolean success = startActivitySafely (v, intent, item);
            ...
        }

        public boolean startActivitySafely(View v, Intent intent, ItemInfo item) {
            ...
            intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
            ...
            startActivity(intent, optsBundle);
            ...
        }

这样 app 冷启动和 Activity 启动 Activity 就联系起来了,app 冷启动相比多了一步获取目标 app 信息构建 intent 过程,然后都会走 Activity.startActivity() 这

2. Activity.startActivity()

现在我们进入 Activity 源码里面了,源码的话我们不用看的细节,了解过程就成

Activity.startActivity() 调的是 startActivityForResult(), startActivityForResult() 方法会使用 mInstrumentation.execStartActivity()

// 
        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);
            }
        }

        public void startActivityForResult(@RequiresPermission Intent intent, int requestCode,
                @Nullable Bundle options) {
            ...
            Instrumentation.ActivityResult ar =
            mInstrumentation.execStartActivity(
                    this, mMainThread.getApplicationThread(), mToken, this,
                    intent, requestCode, options);
            ...
        }
3. mInstrumentation.execStartActivity

mInstrumentation 看过上面大家都知道了把,是 Activity 的 P 层,封装了所有 Activity 的核心业务操作

mInstrumentation.execStartActivity 里面会调 ActivityManager.startActivity ,ActivityManager 知道了吧,是 Activity 与 ActivityManagerService 的远程 AIDL 通讯类,并把反向 AIDL 通讯对象 ApplicationThread 传给远程 ActivityManagerService , 方便 ActivityManagerService 回调,这样看 Activity 把创建 Activity 的任务交给了 远程 ActivityManagerService

//
        public ActivityResult execStartActivity(
                Context who, IBinder contextThread, IBinder token, Activity target,
                Intent intent, int requestCode, Bundle options) {
            ...
            try {
                ...
                // 这个 whoThread 就是 ApplicationThread 反向 AIDL 通讯对象
                int result = ActivityManager.getService()
                        .startActivity(whoThread, who.getBasePackageName(), intent,
                                intent.resolveTypeIfNeeded(who.getContentResolver()),
                                token, target != null ? target.mEmbeddedID : null,
                requestCode, 0, null, options);
                ...
            } catch (RemoteException e) {
                ...
            }
            return null;
        }
4. ActivityManagerService.startActivity

这是代码 脱离 Ui 所在进程来到了系统 ActivityManagerService 进程,ActivityManagerService 会怎么干呢,我们拭目以待

来看代码

// 
        @Override
        public final int startActivity(IApplicationThread caller, String callingPackage,
        Intent intent, String resolvedType, IBinder resultTo, String resultWho, int requestCode,
        int startFlags, ProfilerInfo profilerInfo, Bundle bOptions) {
            return startActivityAsUser(caller, callingPackage, intent, resolvedType, resultTo,
                    resultWho, requestCode, startFlags, profilerInfo, bOptions,
                    UserHandle.getCallingUserId());
        }

ActivityManagerService 的 startActivity 里面多次调用了其他方法:

  • startActivity()
  • -> ActivityStarter.startActivityMayWait()
  • -> ActivityStarter.startActivityLocked()
  • -> ActivityStarter.startActivity()
  • -> ActivityStarter.startActivityUnchecked()
  • -> ActivityStackSupervisor.resumeFocusedStackTopActivityLocked()
  • -> ActivityStack.resumeTopActivityUncheckedLocked()
  • -> ActivityStack.resumeTopActivityInnerLocked()
  • -> ActivityStackSupervisor.startSpecificActivityLocked()

上面的这一柳方法一个调一个,一直到在 tartSpecificActivityLocked 这个方法里才能看到核心内容,这个方法中会判断目标进程是否存在,存在则通知进程启动 Activity,否则就先将进程创建出来

void startSpecificActivityLocked(ActivityRecord r,
        boolean andResume, boolean checkConfig) {
    ...
    if (app != null && app.thread != null) {
        ...
        // 如果进程已存在,则通知进程启动组件
        realStartActivityLocked(r, app, andResume, checkConfig);
        return;
        ...
    }
    // 否则先将进程创建出来
    mService.startProcessLocked(r.processName, r.info.applicationInfo, true, 0,
            "activity", r.intent.getComponent(), false, false, true);
    ...
}

private final void startProcessLocked(ProcessRecord app, String hostingType,
        String hostingNameStr, String abiOverride, String entryPoint, String[] entryPointArgs) {
    ...
    if (entryPoint == null) entryPoint = "android.app.ActivityThread";
    startResult = Process.start(entryPoint,
            app.processName, uid, uid, gids, debugFlags, mountExternal,
            app.info.targetSdkVersion, seInfo, requiredAbi, instructionSet,
            app.info.dataDir, invokeWith, entryPointArgs);
    ...
}
5. ActivityManagerService.realStartActivityLocked 创建新 Activity

我们先来看 realStartActivityLocked 这个方法,这个方法会通过 ApplicationThread 回调 UI 进程创建一个 Activity 出来,app.thread 就是我们之前传递过去的 ApplicationThread AIDL 反向回调

        final boolean realStartActivityLocked(ActivityRecord r, ProcessRecord app,
                boolean andResume, boolean checkConfig) throws RemoteException {
            //...code

            app.thread.scheduleLaunchActivity(new Intent (r.intent), r.appToken,
                    System.identityHashCode(r), r.info,
                    // TODO: Have this take the merged configuration instead of separate global and
                    // override configs.
                    mergedConfiguration.getGlobalConfiguration(),
                    mergedConfiguration.getOverrideConfiguration(), r.compat,
                    r.launchedFromPackage, task.voiceInteractor, app.repProcState, r.icicle,
                    r.persistentState, results, newIntents, !andResume,
                    mService.isNextTransitionForward(), profilerInfo);

            //...code
        }

大家记住 realStartActivityLocked 这个方法,因为一会我们还会提到他,记住是这个方法让我们开始创建 Activity 对象

6. Process.start 创建目标进程

在 4 中,我们看到 ActivityManagerService 会判断目标进程存不存在,不存在就 fork 一个新的进程出来,Process.start 就是创建进程的代码

系统在 fork 一个新的进程后,会在新的进程里面启动 Ui 线程,也就是 ActivtyThread 对象,而 ActivtyThread.main() 方法才是一个 app 进程真正的开始‘

public static void main(String[] args){
    ...
    Looper.prepareMainLooper(); 
    //初始化Looper
    ...
    ActivityThread thread = new ActivityThread();
    //实例化一个ActivityThread
    thread.attach(false);
    //这个方法最后就是为了发送出创建Application的消息
    ... 
    Looper.loop();
    //主线程进入无限循环状态,等待接收消息
}

mian 方法中,先把 UI 线程的 looper 消息队列准备好,然后 new 一个 UI 线程对象,然后初始化 UI 线程的参数,最后把 UI 线程的 looper 消息队列跑起来,UI 线程进入等待任务阶段

这里面我们需要详细看看 thread.attach(false) UI 线程初始化参数方法干了什么

public void attach(boolean system){
    ...
    final IActivityManager mgr = ActivityManagerNative.getDefault();  
    //获得IActivityManager实例,下面会看看它是个啥
    try {
        mgr.attachApplication(mAppThread);
         //看见没?关键啊。mAppThread这个参数下面也会说一下
    } catch (RemoteException ex) {
        throw ex.rethrowFromSystemServer();
    }
    ...
}

恩,可以看到我们把 AIDL 反向回调通讯注册到了 ActivityManagerService 里面,然后那必然操作又切回到了系统的 ActivityManagerService 进程里,接着 ActivityManagerService 里面的代码走到了 attachApplicationLocked 这个位置

attachApplicationLocked 方法很重要,期中执行了2个操作,先创建 application 对象,再创建 Activity 对象,这2个方法可是串行执行的,都是 AIDL 远程操作

// 
private final boolean attachApplicationLocked(IApplicationThread thread,
        int pid) {
    ....
    // 创建 application 对象
    thread.bindApplication(processName, appInfo, providers,
            app.instr.mClass,
            profilerInfo, app.instr.mArguments,
            app.instr.mWatcher,
            app.instr.mUiAutomationConnection, testMode,
            mBinderTransactionTrackingEnabled, enableTrackAllocation,
            isRestrictedBackupMode || !normalMode, app.persistent,
            new Configuration(getGlobalConfiguration()), app.compat,
            getCommonServicesLocked(app.isolated),
            mCoreSettingsObserver.getCoreSettingsLocked(),
            buildSerial);
    ...

    // 然后再创建 Activity 对象
    if (normalMode) {
        try {
            if (mStackSupervisor.attachApplicationLocked(app)) {
                didSomething = true;
            }
        } catch (Exception e) {
            ...
        }
    }
    ...
}

boolean attachApplicationLocked(ProcessRecord app) throws RemoteException {
    final String processName = app.processName;
    ...
    if (realStartActivityLocked(activity, app,
            top == activity /* andResume */, true /* checkConfig */)) {
        ...
    }
    ...
}

final boolean realStartActivityLocked(ActivityRecord r, ProcessRecord app,
        boolean andResume, boolean checkConfig) throws RemoteException {
    ...
    app.thread.scheduleLaunchActivity(new Intent(r.intent), r.appToken,
            System.identityHashCode(r), r.info,
            // TODO: Have this take the merged configuration instead of separate global
            // and override configs.
            mergedConfiguration.getGlobalConfiguration(),
            mergedConfiguration.getOverrideConfiguration(), r.compat,
            r.launchedFromPackage, task.voiceInteractor, app.repProcState, r.icicle,
            r.persistentState, results, newIntents, !andResume,
            mService.isNextTransitionForward(), profilerInfo);
    ...
7. UI 线程接受消息,new application 对象

可以看见 attachApplicationLocked 又通过 ApplicationThread 回调,让 UI 进程干活了,注意这个 ApplicationThread 所在的进程就不是我们发起 startActivity 的 LaunchActivity 所在的进程了,而是我们刚刚 fork 出来的目标进程了

接着我们来看看 UI 进程的 bindApplication 方法

public final void bindApplication(String processName, ApplicationInfo appInfo,
        List<ProviderInfo> providers, ComponentName instrumentationName,
        ProfilerInfo profilerInfo, Bundle instrumentationArgs,
        IInstrumentationWatcher instrumentationWatcher,
        IUiAutomationConnection instrumentationUiConnection, int debugMode,
        boolean enableBinderTracking, boolean trackAllocation,
        boolean isRestrictedBackupMode, boolean persistent, Configuration config,
        CompatibilityInfo compatInfo, Map services, Bundle coreSettings,
        String buildSerial) {
    ...
    sendMessage(H.BIND_APPLICATION, data);
}

private void sendMessage(int what, Object obj) {
    sendMessage(what, obj, 0, 0, false);
}

private void sendMessage(int what, Object obj, int arg1, int arg2, boolean async) {
    if (DEBUG_MESSAGES) 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;
    if (async) {
        msg.setAsynchronous(true);
    }
    mH.sendMessage(msg);
}

ApplicationThread 发送了一个 H.BIND_APPLICATION 的消息,该消息会由 ActivityThread 一个名叫 H 的 handle内部类接收

// 
public void handleMessage(Message msg) {
    ...
    switch (msg.what) {
        ...
        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;
        ...
    }
}

private void handleBindApplication(AppBindData data) {
    ...
    final InstrumentationInfo ii;
    ...
    // 创建 mInstrumentation 实例
    if (ii != null) {
        final ApplicationInfo instrApp = new ApplicationInfo();
        ii.copyTo(instrApp);
        instrApp.initForUser(UserHandle.myUserId());
        final LoadedApk pi = getPackageInfo(instrApp, data.compatInfo,
                appContext.getClassLoader(), false, true, false);
        final ContextImpl instrContext = ContextImpl.createAppContext(this, pi);

        try {
            final ClassLoader cl = instrContext.getClassLoader();
            mInstrumentation = (Instrumentation)
                cl.loadClass(data.instrumentationName.getClassName()).newInstance();
        } catch (Exception e) {
            ...
        }
        ...
    } else {
        mInstrumentation = new Instrumentation();
    }
    ...
    Application app;
    ...
    // 创建 Application 实例
    try {
        ...
        app = data.info.makeApplication(data.restrictedBackupMode, null);
        mInitialApplication = app;
        ...
        try {
            mInstrumentation.callApplicationOnCreate(app);
        } catch (Exception e) {
            ...
        }
    } finally {
        ...
    }
    ...
}

public Application makeApplication(boolean forceDefaultAppClass,
        Instrumentation instrumentation) {
    Application app = null;

    String appClass = mApplicationInfo.className;
    if (forceDefaultAppClass || (appClass == null)) {
        appClass = "android.app.Application";
    }

    try {
        java.lang.ClassLoader cl = getClassLoader();
        ...
        ContextImpl appContext = ContextImpl.createAppContext(mActivityThread, this);
        app = mActivityThread.mInstrumentation.newApplication(
                cl, appClass, appContext);
        appContext.setOuterContext(app);
    } catch (Exception e) {
        ...
    }
    mActivityThread.mAllApplications.add(app);
    mApplication = app;

    if (instrumentation != null) {// 传入为 null 所以不走
        try {
            instrumentation.callApplicationOnCreate(app);
        } catch (Exception e) {
            ...
        }
    }
    ...
    return app;
}

static public Application newApplication(Class<?> clazz, Context context)
        throws InstantiationException, IllegalAccessException,
        ClassNotFoundException {
    Application app = (Application)clazz.newInstance();
    app.attach(context);
    return app;
}

该 handle 会创建一个 mInstrumentation 实例,然后创建出上下文对象,application 对象,application 绑定上下文,mInstrumentation 对象会执行 application.onCreate() 初始化

8. UI 线程接受消息,new activity 对象

在6里面,ActivityManagerService.attachApplicationLocked() 里面连着干了2件事,先创建 application ,完事再创建 activity 对象,在7里面我们创建完了 application 对象,下面就该创建 activity 对象了

到这 app 冷启动有和 activity 启动 activity 走到一起了,之后2者也没分别了,差别就是 app 冷启动多了创建 application 对象的过程,完事都一样了,就是 创建 activity 对象了

//
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) {
    ...
    sendMessage(H.LAUNCH_ACTIVITY, r);
}

ApplicationThread.scheduleLaunchActivity() 方法里发送一个 H.LAUNCH_ACTIVITY 创建 activity 对象的消息

然后 ActivityThread 的 handle 接受消息,由 Instrumentation new activity 对象,activity 对象初始化参数,最后由 Instrumentation 执行 activity.onCreate() 初始化方法

// 
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) {
    ...
    sendMessage(H.LAUNCH_ACTIVITY, r);
}

public void handleMessage(Message msg) {
    ...
    switch (msg.what) {
        ...
        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, "LAUNCH_ACTIVITY");
            Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
        } break;
        ...
    }
}

private void handleLaunchActivity(ActivityClientRecord r, Intent customIntent, String reason) {
    ...
    Activity a = performLaunchActivity(r, customIntent);
    ...
}

private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
    ...
    Activity activity = null;
    try {
        java.lang.ClassLoader cl = appContext.getClassLoader();
        activity = mInstrumentation.newActivity(
                cl, component.getClassName(), r.intent);
        ...
    } catch (Exception e) {
        ...
    }

    try {
        // 返回之前创建过的 application 对象
        Application app = r.packageInfo.makeApplication(false, mInstrumentation);
        ...
        if (activity != null) {
            ...
            // attach 到 window 上
            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, window, r.configCallback);
            ...
            if (r.isPersistable()) {
                mInstrumentation.callActivityOnCreate(activity, r.state, r.persistentState);
            } else {
                mInstrumentation.callActivityOnCreate(activity, r.state);
            }
            ...
        }
    } catch (Exception e) {
        ...
    }
    return activity;
}

public Activity newActivity(ClassLoader cl, String className,
        Intent intent)
        throws InstantiationException, IllegalAccessException,
        ClassNotFoundException {
    return (Activity)cl.loadClass(className).newInstance();
}

public Activity newActivity(Class<?> clazz, Context context,
        IBinder token, Application application, Intent intent, ActivityInfo info,
        CharSequence title, Activity parent, String id,
        Object lastNonConfigurationInstance) throws InstantiationException,
        IllegalAccessException {
    Activity activity = (Activity)clazz.newInstance();
    ActivityThread aThread = null;
    activity.attach(context, aThread, this, token, 0 /* ident */, application, intent,
            info, title, parent, id,
            (Activity.NonConfigurationInstances)lastNonConfigurationInstance,
            new Configuration(), null /* referrer */, null /* voiceInteractor */,
            null /* window */, null /* activityConfigCallback */);
    return activity;
}

到这 activity 的创建流程算是完事了,之后走 activity 的生命周期函数,再由 window 渲染界面显示,但是这里我们还要看看 activity.attach方法,看看 activity 初始化了什么参数,方面之后我们继续说 window

        final void attach(Context context, ActivityThread aThread,
                Instrumentation instr, IBinder token, int ident,
                Application application, Intent intent, ActivityInfo info,
                CharSequence title, Activity parent, String id,
                NonConfigurationInstances lastNonConfigurationInstances,
                Configuration config, String referrer, IVoiceInteractor voiceInteractor,
                Window window) {
            attachBaseContext(context);

            mFragments.attachHost(null /*parent*/);

            mWindow = new PhoneWindow (this, window);
            mWindow.setWindowControllerCallback(this);
            mWindow.setCallback(this);
            mWindow.setOnWindowDismissedCallback(this);
            mWindow.getLayoutInflater().setPrivateFactory(this);
            if (info.softInputMode != WindowManager.LayoutParams.SOFT_INPUT_STATE_UNSPECIFIED) {
                mWindow.setSoftInputMode(info.softInputMode);
            }
            if (info.uiOptions != 0) {
                mWindow.setUiOptions(info.uiOptions);
            }
            mUiThread = Thread.currentThread();

            mMainThread = aThread;
            mInstrumentation = instr;
            mToken = token;
            mIdent = ident;
            mApplication = application;
            mIntent = intent;
            mReferrer = referrer;
            mComponent = intent.getComponent();
            mActivityInfo = info;
            mTitle = title;
            mParent = parent;
            mEmbeddedID = id;
            mLastNonConfigurationInstances = lastNonConfigurationInstances;
            if (voiceInteractor != null) {
                if (lastNonConfigurationInstances != null) {
                    mVoiceInteractor = lastNonConfigurationInstances.voiceInteractor;
                } else {
                    mVoiceInteractor = new VoiceInteractor (voiceInteractor, this, this,
                    Looper.myLooper());
                }
            }

            mWindow.setWindowManager(
                    (WindowManager) context . getSystemService (Context.WINDOW_SERVICE),
                    mToken, mComponent.flattenToString(),
                    (info.flags & ActivityInfo . FLAG_HARDWARE_ACCELERATED) != 0);
            if (mParent != null) {
                mWindow.setContainer(mParent.getWindow());
            }
            mWindowManager = mWindow.getWindowManager();
            mCurrentConfig = config;
        }

创建了 PhoneWindow 窗口,给窗口对象注册监听,通过窗口Window创建,初始参数赋值,把和 WindowManagerService 远程通讯的 WindowManagerImpl AIDL 对象绑定给 PhoneWindow


参考文章:

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 217,185评论 6 503
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,652评论 3 393
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 163,524评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,339评论 1 293
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,387评论 6 391
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,287评论 1 301
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,130评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,985评论 0 275
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,420评论 1 313
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,617评论 3 334
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,779评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,477评论 5 345
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,088评论 3 328
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,716评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,857评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,876评论 2 370
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,700评论 2 354

推荐阅读更多精彩内容