区块链技术博客
www.b2bchain.cn

为什么不能使用 Application Context 显示 Dialog?求职学习资料

本文介绍了为什么不能使用 Application Context 显示 Dialog?求职学习资料,有助于帮助完成毕业设计以及求职,是一篇很好的资料。

对技术面试,学习经验等有一些体会,在此分享。

Android 复习笔记目录

  1. 唠唠任务栈,返回栈和生命周期
  2. 唠唠 Activity 的生命周期
  3. 扒一扒 Context
  4. 为什么不能使用 Application Context 显示 Dialog?

本文永久更新地址: https://xiaozhuanlan.com/topic/3958126407

目录

  • 为什么不能使用 Application Context 显示 Dialog?
  • 谁创建了 Token?
  • WMS 是如何拿到 Token 的?
  • WMS 是如何校验 Token 的?

为什么不能使用 Application Context 显示 Dialog?

在上一篇文章 扒一扒 Context 中遗留了一个问题:

为什么不能使用 Application Context 显示 Dialog ?

写个简单的测试代码,如下:

Dialog dialog = new Dialog(getApplicationContext()); dialog.show();

运行时会得到这样一个错误:

Caused by: android.view.WindowManager$BadTokenException: Unable to add window -- token null is not valid; is your activity running?         at android.view.ViewRootImpl.setView(ViewRootImpl.java:951)         at android.view.WindowManagerGlobal.addView(WindowManagerGlobal.java:387)         at android.view.WindowManagerImpl.addView(WindowManagerImpl.java:96)         at android.app.Dialog.show(Dialog.java:344)         at luyao.android.context.ContextActivity.showDialog(ContextActivity.java:31)

看到报错信息中的 token ,不知道你还记不记得上篇文章中介绍过的 Activity.attach() 方法:

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, ActivityConfigCallback activityConfigCallback) {     // 回调 attachBaseContext()     attachBaseContext(context);      ......      // 创建 PhoneWindow     mWindow = new PhoneWindow(this, window, activityConfigCallback);      ......          // 第二个参数是 mToken     mWindow.setWindowManager(             (WindowManager)context.getSystemService(Context.WINDOW_SERVICE),             mToken, mComponent.flattenToString(),             (info.flags & ActivityInfo.FLAG_HARDWARE_ACCELERATED) != 0);     ...... }

Activity 被创建之后会调用 attach() 方法,做了这么几件事:

  • 创建了 PhoneWindow 对象 mWondow
  • 给当前 window 绑定 mToken
  • ……

这里的 IBinder 对象 mToken 很重要。它是一个 Binder 对象,可以在 app 进程,system_server 进程之间进行传递。和我们通常所说的 Token 一样,这里也可以把它看做是一种特殊的令牌,用来标识 Window ,在对 Window 进行视图操作的时候就可以做一些校验工作。

所以,Activity 对应的 Window/WMS 都是持有这个 mToken 的。结合之前 Application 创建 Dialog 的报错信息,我们可以大胆猜测 Application Context 创建 Dialog 的过程中,并没有实例化类似的 token。

回到 Dialog 的构造函数中,

Dialog(@NonNull Context context, @StyleRes int themeResId, boolean createContextThemeWrapper) {     ......      // 获取 WindowManager     mWindowManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);      final Window w = new PhoneWindow(mContext);     mWindow = w;     ...... }

根据传入的 Context 调用 getSystemService(Context.WINDOW_SERVICE) 方法来得到 WindowManager 对象 mWindowManager ,最终会通过 mWindowManager.addWindow() 来显示 dialog 。

如果传入的 Context 是 Activity,返回的是在 Activity.attach() 方法中创建的 mWindowManager 对象,这个时候 mToken 也已经绑定。

> Activity.java  @Override public Object getSystemService(@ServiceName @NonNull String name) {     ......      if (WINDOW_SERVICE.equals(name)) {         return mWindowManager; // 在 attach() 方法中已经实例化     } else if (SEARCH_SERVICE.equals(name)) {         ensureSearchManager();         return mSearchManager;     }     return super.getSystemService(name); }

如果传入的 Context 是 Application,最终调用的是父类 ContextImpl 的方法。

@Override public Object getSystemService(String name) {     return SystemServiceRegistry.getSystemService(this, name); }

SystemServiceRegistry.getSystemService(this, name) 拿到的是已经提前初始化完成并缓存下来的系统服务,并没有携带任何的 Token。

registerService(Context.WINDOW_SERVICE, WindowManager.class,                 new CachedServiceFetcher<WindowManager>() {             @Override             public WindowManager createService(ContextImpl ctx) {                 return new WindowManagerImpl(ctx);             }});

所以,Android 不允许 Activity 以外的 Context 来创建和显示普通的 Dialog 。 这里的 普通 指的是文章开头示例代码中的普通 Dialog,并非 Toast,System Dialog 等等。Android 系统为了安全考虑,不想在 App 进入后台之后仍然可以弹出 Dialog,这样就会产生可以在其他 App 中弹窗的场景,造成一定的安全隐患。虽然通过 Dialog Theme 的 Activity 仍然可以实现这一需求,但是 Google 也在加强 对后台启动 Activity 的限制。

写到这里,问题似乎已经得到了解答。但是其实我们对于整个 Token 流程还是一片雾水的。试着想一下下面几个问题。

  • mToken 是在什么时机,什么地方创建的?
  • WMS 是如何拿到 mToken 的?
  • WMS 是如何校验 token 的?
  • ……

真正掌握了这些问题之后,才能形成一个完整的知识闭环,但伴随而来的,是逃避不了的,枯燥乏味的 Read the fucking AOSP 。

谁创建了 Token?

先来看看 Token 到底是个什么样的类。

> ActivityRecord.java  static class Token extends IApplicationToken.Stub {     private final WeakReference<ActivityRecord> weakActivity;     private final String name;      Token(ActivityRecord activity, Intent intent) {         weakActivity = new WeakReference<>(activity);         name = intent.getComponent().flattenToShortString();     }      ...... }

TokenActivityRecord 的静态内部类,它持有外部 ActivityRecord 的弱引用。继承自 IApplicationToken.Stub ,是一个 Binder 对象。它在 ActivityRecord 的构造函数中初始化。

> ActivityRecord.java  ActivityRecord(ActivityManagerService _service, ProcessRecord _caller, int _launchedFromPid,             int _launchedFromUid, String _launchedFromPackage, Intent _intent, String _resolvedType,             ActivityInfo aInfo, Configuration _configuration,             ActivityRecord _resultTo, String _resultWho, int _reqCode,             boolean _componentSpecified, boolean _rootVoiceInteraction,             ActivityStackSupervisor supervisor, ActivityOptions options,             ActivityRecord sourceRecord) {     service = _service;     // 初始化 appToken     appToken = new Token(this, _intent);     ...... }

一个 ActivtyRecord 代表一个 Activity 实例, 它包含了 Activity 的所有信息。在 Activity 的启动过程中,当执行到 ActivityStarter.startActivity() 时,会创建待启动的 ActivityRecord 对象,也间接创建了 Token 对象。

> ActivityStarter.java  private int startActivity(IApplicationThread caller, Intent intent, Intent ephemeralIntent,             String resolvedType, ActivityInfo aInfo, ResolveInfo rInfo,             IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor,             IBinder resultTo, String resultWho, int requestCode, int callingPid, int callingUid,             String callingPackage, int realCallingPid, int realCallingUid, int startFlags,             SafeActivityOptions options,             boolean ignoreTargetSecurity, boolean componentSpecified, ActivityRecord[] outActivity,             TaskRecord inTask, boolean allowPendingRemoteAnimationRegistryLookup,             PendingIntentRecord originatingPendingIntent) {              ......              // 构建 ActivityRecord,其中会初始化 token             ActivityRecord r = new ActivityRecord(mService, callerApp, callingPid, callingUid,                 callingPackage, intent, resolvedType, aInfo, mService.getGlobalConfiguration(),                 resultRecord, resultWho, requestCode, componentSpecified, voiceSession != null,                 mSupervisor, checkedOptions, sourceRecord);              ......             return startActivity(r, sourceRecord, voiceSession, voiceInteractor, startFlags,                 true /* doResume */, checkedOptions, inTask, outActivity); }

到这里, ActivityRecord.appToken 已经被赋值。所以 Token 是在 AMS 的 startActivity 流程中创建的。但是 Token 的校验显然是发生在 WMS 中的,所以 AMS 还得把 Token 交到 WMS 。

WMS 是如何拿到 Token 的?

继续跟下去,startActivity() 最后会调用到 ActivityStack.startActivityLocked(),这个方法就是把 Token 给到 WMS 的关键。

Android 复习笔记目录

  1. 唠唠任务栈,返回栈和生命周期
  2. 唠唠 Activity 的生命周期
  3. 扒一扒 Context
  4. 为什么不能使用 Application Context 显示 Dialog?

本文永久更新地址: https://xiaozhuanlan.com/topic/3958126407

目录

  • 为什么不能使用 Application Context 显示 Dialog?
  • 谁创建了 Token?
  • WMS 是如何拿到 Token 的?
  • WMS 是如何校验 Token 的?

为什么不能使用 Application Context 显示 Dialog?

在上一篇文章 扒一扒 Context 中遗留了一个问题:

为什么不能使用 Application Context 显示 Dialog ?

写个简单的测试代码,如下:

Dialog dialog = new Dialog(getApplicationContext()); dialog.show();

运行时会得到这样一个错误:

Caused by: android.view.WindowManager$BadTokenException: Unable to add window -- token null is not valid; is your activity running?         at android.view.ViewRootImpl.setView(ViewRootImpl.java:951)         at android.view.WindowManagerGlobal.addView(WindowManagerGlobal.java:387)         at android.view.WindowManagerImpl.addView(WindowManagerImpl.java:96)         at android.app.Dialog.show(Dialog.java:344)         at luyao.android.context.ContextActivity.showDialog(ContextActivity.java:31)

看到报错信息中的 token ,不知道你还记不记得上篇文章中介绍过的 Activity.attach() 方法:

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, ActivityConfigCallback activityConfigCallback) {     // 回调 attachBaseContext()     attachBaseContext(context);      ......      // 创建 PhoneWindow     mWindow = new PhoneWindow(this, window, activityConfigCallback);      ......          // 第二个参数是 mToken     mWindow.setWindowManager(             (WindowManager)context.getSystemService(Context.WINDOW_SERVICE),             mToken, mComponent.flattenToString(),             (info.flags & ActivityInfo.FLAG_HARDWARE_ACCELERATED) != 0);     ...... }

Activity 被创建之后会调用 attach() 方法,做了这么几件事:

  • 创建了 PhoneWindow 对象 mWondow
  • 给当前 window 绑定 mToken
  • ……

这里的 IBinder 对象 mToken 很重要。它是一个 Binder 对象,可以在 app 进程,system_server 进程之间进行传递。和我们通常所说的 Token 一样,这里也可以把它看做是一种特殊的令牌,用来标识 Window ,在对 Window 进行视图操作的时候就可以做一些校验工作。

所以,Activity 对应的 Window/WMS 都是持有这个 mToken 的。结合之前 Application 创建 Dialog 的报错信息,我们可以大胆猜测 Application Context 创建 Dialog 的过程中,并没有实例化类似的 token。

回到 Dialog 的构造函数中,

Dialog(@NonNull Context context, @StyleRes int themeResId, boolean createContextThemeWrapper) {     ......      // 获取 WindowManager     mWindowManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);      final Window w = new PhoneWindow(mContext);     mWindow = w;     ...... }

根据传入的 Context 调用 getSystemService(Context.WINDOW_SERVICE) 方法来得到 WindowManager 对象 mWindowManager ,最终会通过 mWindowManager.addWindow() 来显示 dialog 。

如果传入的 Context 是 Activity,返回的是在 Activity.attach() 方法中创建的 mWindowManager 对象,这个时候 mToken 也已经绑定。

> Activity.java  @Override public Object getSystemService(@ServiceName @NonNull String name) {     ......      if (WINDOW_SERVICE.equals(name)) {         return mWindowManager; // 在 attach() 方法中已经实例化     } else if (SEARCH_SERVICE.equals(name)) {         ensureSearchManager();         return mSearchManager;     }     return super.getSystemService(name); }

如果传入的 Context 是 Application,最终调用的是父类 ContextImpl 的方法。

@Override public Object getSystemService(String name) {     return SystemServiceRegistry.getSystemService(this, name); }

SystemServiceRegistry.getSystemService(this, name) 拿到的是已经提前初始化完成并缓存下来的系统服务,并没有携带任何的 Token。

registerService(Context.WINDOW_SERVICE, WindowManager.class,                 new CachedServiceFetcher<WindowManager>() {             @Override             public WindowManager createService(ContextImpl ctx) {                 return new WindowManagerImpl(ctx);             }});

所以,Android 不允许 Activity 以外的 Context 来创建和显示普通的 Dialog 。 这里的 普通 指的是文章开头示例代码中的普通 Dialog,并非 Toast,System Dialog 等等。Android 系统为了安全考虑,不想在 App 进入后台之后仍然可以弹出 Dialog,这样就会产生可以在其他 App 中弹窗的场景,造成一定的安全隐患。虽然通过 Dialog Theme 的 Activity 仍然可以实现这一需求,但是 Google 也在加强 对后台启动 Activity 的限制。

写到这里,问题似乎已经得到了解答。但是其实我们对于整个 Token 流程还是一片雾水的。试着想一下下面几个问题。

  • mToken 是在什么时机,什么地方创建的?
  • WMS 是如何拿到 mToken 的?
  • WMS 是如何校验 token 的?
  • ……

真正掌握了这些问题之后,才能形成一个完整的知识闭环,但伴随而来的,是逃避不了的,枯燥乏味的 Read the fucking AOSP 。

谁创建了 Token?

先来看看 Token 到底是个什么样的类。

> ActivityRecord.java  static class Token extends IApplicationToken.Stub {     private final WeakReference<ActivityRecord> weakActivity;     private final String name;      Token(ActivityRecord activity, Intent intent) {         weakActivity = new WeakReference<>(activity);         name = intent.getComponent().flattenToShortString();     }      ...... }

TokenActivityRecord 的静态内部类,它持有外部 ActivityRecord 的弱引用。继承自 IApplicationToken.Stub ,是一个 Binder 对象。它在 ActivityRecord 的构造函数中初始化。

> ActivityRecord.java  ActivityRecord(ActivityManagerService _service, ProcessRecord _caller, int _launchedFromPid,             int _launchedFromUid, String _launchedFromPackage, Intent _intent, String _resolvedType,             ActivityInfo aInfo, Configuration _configuration,             ActivityRecord _resultTo, String _resultWho, int _reqCode,             boolean _componentSpecified, boolean _rootVoiceInteraction,             ActivityStackSupervisor supervisor, ActivityOptions options,             ActivityRecord sourceRecord) {     service = _service;     // 初始化 appToken     appToken = new Token(this, _intent);     ...... }

一个 ActivtyRecord 代表一个 Activity 实例, 它包含了 Activity 的所有信息。在 Activity 的启动过程中,当执行到 ActivityStarter.startActivity() 时,会创建待启动的 ActivityRecord 对象,也间接创建了 Token 对象。

> ActivityStarter.java  private int startActivity(IApplicationThread caller, Intent intent, Intent ephemeralIntent,             String resolvedType, ActivityInfo aInfo, ResolveInfo rInfo,             IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor,             IBinder resultTo, String resultWho, int requestCode, int callingPid, int callingUid,             String callingPackage, int realCallingPid, int realCallingUid, int startFlags,             SafeActivityOptions options,             boolean ignoreTargetSecurity, boolean componentSpecified, ActivityRecord[] outActivity,             TaskRecord inTask, boolean allowPendingRemoteAnimationRegistryLookup,             PendingIntentRecord originatingPendingIntent) {              ......              // 构建 ActivityRecord,其中会初始化 token             ActivityRecord r = new ActivityRecord(mService, callerApp, callingPid, callingUid,                 callingPackage, intent, resolvedType, aInfo, mService.getGlobalConfiguration(),                 resultRecord, resultWho, requestCode, componentSpecified, voiceSession != null,                 mSupervisor, checkedOptions, sourceRecord);              ......             return startActivity(r, sourceRecord, voiceSession, voiceInteractor, startFlags,                 true /* doResume */, checkedOptions, inTask, outActivity); }

到这里, ActivityRecord.appToken 已经被赋值。所以 Token 是在 AMS 的 startActivity 流程中创建的。但是 Token 的校验显然是发生在 WMS 中的,所以 AMS 还得把 Token 交到 WMS 。

WMS 是如何拿到 Token 的?

继续跟下去,startActivity() 最后会调用到 ActivityStack.startActivityLocked(),这个方法就是把 Token 给到 WMS 的关键。

Android 复习笔记目录

  1. 唠唠任务栈,返回栈和生命周期
  2. 唠唠 Activity 的生命周期
  3. 扒一扒 Context
  4. 为什么不能使用 Application Context 显示 Dialog?

本文永久更新地址: https://xiaozhuanlan.com/topic/3958126407

目录

  • 为什么不能使用 Application Context 显示 Dialog?
  • 谁创建了 Token?
  • WMS 是如何拿到 Token 的?
  • WMS 是如何校验 Token 的?

为什么不能使用 Application Context 显示 Dialog?

在上一篇文章 扒一扒 Context 中遗留了一个问题:

为什么不能使用 Application Context 显示 Dialog ?

写个简单的测试代码,如下:

Dialog dialog = new Dialog(getApplicationContext()); dialog.show();

运行时会得到这样一个错误:

Caused by: android.view.WindowManager$BadTokenException: Unable to add window -- token null is not valid; is your activity running?         at android.view.ViewRootImpl.setView(ViewRootImpl.java:951)         at android.view.WindowManagerGlobal.addView(WindowManagerGlobal.java:387)         at android.view.WindowManagerImpl.addView(WindowManagerImpl.java:96)         at android.app.Dialog.show(Dialog.java:344)         at luyao.android.context.ContextActivity.showDialog(ContextActivity.java:31)

看到报错信息中的 token ,不知道你还记不记得上篇文章中介绍过的 Activity.attach() 方法:

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, ActivityConfigCallback activityConfigCallback) {     // 回调 attachBaseContext()     attachBaseContext(context);      ......      // 创建 PhoneWindow     mWindow = new PhoneWindow(this, window, activityConfigCallback);      ......          // 第二个参数是 mToken     mWindow.setWindowManager(             (WindowManager)context.getSystemService(Context.WINDOW_SERVICE),             mToken, mComponent.flattenToString(),             (info.flags & ActivityInfo.FLAG_HARDWARE_ACCELERATED) != 0);     ...... }

Activity 被创建之后会调用 attach() 方法,做了这么几件事:

  • 创建了 PhoneWindow 对象 mWondow
  • 给当前 window 绑定 mToken
  • ……

这里的 IBinder 对象 mToken 很重要。它是一个 Binder 对象,可以在 app 进程,system_server 进程之间进行传递。和我们通常所说的 Token 一样,这里也可以把它看做是一种特殊的令牌,用来标识 Window ,在对 Window 进行视图操作的时候就可以做一些校验工作。

所以,Activity 对应的 Window/WMS 都是持有这个 mToken 的。结合之前 Application 创建 Dialog 的报错信息,我们可以大胆猜测 Application Context 创建 Dialog 的过程中,并没有实例化类似的 token。

回到 Dialog 的构造函数中,

Dialog(@NonNull Context context, @StyleRes int themeResId, boolean createContextThemeWrapper) {     ......      // 获取 WindowManager     mWindowManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);      final Window w = new PhoneWindow(mContext);     mWindow = w;     ...... }

根据传入的 Context 调用 getSystemService(Context.WINDOW_SERVICE) 方法来得到 WindowManager 对象 mWindowManager ,最终会通过 mWindowManager.addWindow() 来显示 dialog 。

如果传入的 Context 是 Activity,返回的是在 Activity.attach() 方法中创建的 mWindowManager 对象,这个时候 mToken 也已经绑定。

> Activity.java  @Override public Object getSystemService(@ServiceName @NonNull String name) {     ......      if (WINDOW_SERVICE.equals(name)) {         return mWindowManager; // 在 attach() 方法中已经实例化     } else if (SEARCH_SERVICE.equals(name)) {         ensureSearchManager();         return mSearchManager;     }     return super.getSystemService(name); }

如果传入的 Context 是 Application,最终调用的是父类 ContextImpl 的方法。

@Override public Object getSystemService(String name) {     return SystemServiceRegistry.getSystemService(this, name); }

SystemServiceRegistry.getSystemService(this, name) 拿到的是已经提前初始化完成并缓存下来的系统服务,并没有携带任何的 Token。

registerService(Context.WINDOW_SERVICE, WindowManager.class,                 new CachedServiceFetcher<WindowManager>() {             @Override             public WindowManager createService(ContextImpl ctx) {                 return new WindowManagerImpl(ctx);             }});

所以,Android 不允许 Activity 以外的 Context 来创建和显示普通的 Dialog 。 这里的 普通 指的是文章开头示例代码中的普通 Dialog,并非 Toast,System Dialog 等等。Android 系统为了安全考虑,不想在 App 进入后台之后仍然可以弹出 Dialog,这样就会产生可以在其他 App 中弹窗的场景,造成一定的安全隐患。虽然通过 Dialog Theme 的 Activity 仍然可以实现这一需求,但是 Google 也在加强 对后台启动 Activity 的限制。

写到这里,问题似乎已经得到了解答。但是其实我们对于整个 Token 流程还是一片雾水的。试着想一下下面几个问题。

  • mToken 是在什么时机,什么地方创建的?
  • WMS 是如何拿到 mToken 的?
  • WMS 是如何校验 token 的?
  • ……

真正掌握了这些问题之后,才能形成一个完整的知识闭环,但伴随而来的,是逃避不了的,枯燥乏味的 Read the fucking AOSP 。

谁创建了 Token?

先来看看 Token 到底是个什么样的类。

> ActivityRecord.java  static class Token extends IApplicationToken.Stub {     private final WeakReference<ActivityRecord> weakActivity;     private final String name;      Token(ActivityRecord activity, Intent intent) {         weakActivity = new WeakReference<>(activity);         name = intent.getComponent().flattenToShortString();     }      ...... }

TokenActivityRecord 的静态内部类,它持有外部 ActivityRecord 的弱引用。继承自 IApplicationToken.Stub ,是一个 Binder 对象。它在 ActivityRecord 的构造函数中初始化。

> ActivityRecord.java  ActivityRecord(ActivityManagerService _service, ProcessRecord _caller, int _launchedFromPid,             int _launchedFromUid, String _launchedFromPackage, Intent _intent, String _resolvedType,             ActivityInfo aInfo, Configuration _configuration,             ActivityRecord _resultTo, String _resultWho, int _reqCode,             boolean _componentSpecified, boolean _rootVoiceInteraction,             ActivityStackSupervisor supervisor, ActivityOptions options,             ActivityRecord sourceRecord) {     service = _service;     // 初始化 appToken     appToken = new Token(this, _intent);     ...... }

一个 ActivtyRecord 代表一个 Activity 实例, 它包含了 Activity 的所有信息。在 Activity 的启动过程中,当执行到 ActivityStarter.startActivity() 时,会创建待启动的 ActivityRecord 对象,也间接创建了 Token 对象。

> ActivityStarter.java  private int startActivity(IApplicationThread caller, Intent intent, Intent ephemeralIntent,             String resolvedType, ActivityInfo aInfo, ResolveInfo rInfo,             IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor,             IBinder resultTo, String resultWho, int requestCode, int callingPid, int callingUid,             String callingPackage, int realCallingPid, int realCallingUid, int startFlags,             SafeActivityOptions options,             boolean ignoreTargetSecurity, boolean componentSpecified, ActivityRecord[] outActivity,             TaskRecord inTask, boolean allowPendingRemoteAnimationRegistryLookup,             PendingIntentRecord originatingPendingIntent) {              ......              // 构建 ActivityRecord,其中会初始化 token             ActivityRecord r = new ActivityRecord(mService, callerApp, callingPid, callingUid,                 callingPackage, intent, resolvedType, aInfo, mService.getGlobalConfiguration(),                 resultRecord, resultWho, requestCode, componentSpecified, voiceSession != null,                 mSupervisor, checkedOptions, sourceRecord);              ......             return startActivity(r, sourceRecord, voiceSession, voiceInteractor, startFlags,                 true /* doResume */, checkedOptions, inTask, outActivity); }

到这里, ActivityRecord.appToken 已经被赋值。所以 Token 是在 AMS 的 startActivity 流程中创建的。但是 Token 的校验显然是发生在 WMS 中的,所以 AMS 还得把 Token 交到 WMS 。

WMS 是如何拿到 Token 的?

继续跟下去,startActivity() 最后会调用到 ActivityStack.startActivityLocked(),这个方法就是把 Token 给到 WMS 的关键。

部分转自互联网,侵权删除联系

赞(0) 打赏
部分文章转自网络,侵权联系删除b2bchain区块链学习技术社区 » 为什么不能使用 Application Context 显示 Dialog?求职学习资料
分享到: 更多 (0)

评论 抢沙发

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址

b2b链

联系我们联系我们