参考:<Android 内核剖析>
最近看WMS, 很多地方都会出现Token的身影, 因为AMS中也有Token, 想试着总结下.
Activity中mToken由来
//第一 Activity.java
//第始于在Activity中调用startActivity()
public void startActivity(Intent intent) {
startActivityForResult(intent, -1);
}
//第二 Activity.java
public void startActivityForResult(Intent intent, int requestCode) {
...
Instrumentation.ActivityResult ar = mInstrumentation.execStartActivity(
this, mMainThread.getApplicationThread(), mToken, this,intent, requestCode);
...
}
//第三 Instrumentation.java
public ActivityResult execStartActivity(Context who, IBinder contextThread, IBinder token, Activity target,Intent intent, int requestCode) {
try {
// getDefault() 获取AMS代理对象,执行AMS中的startActivity()
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;
}
//第四 ActivityManagerService.java
public final int startActivity(IApplicationThread caller,
Intent intent, String resolvedType, Uri[] grantedUriPermissions,
int grantedMode, IBinder resultTo,
String resultWho, int requestCode, boolean onlyIfNeeded,
boolean debug) {
// WMS很多具体的操作都会交由它来处理
return mMainStack.startActivityMayWait(caller, intent, resolvedType,
grantedUriPermissions, grantedMode, resultTo, resultWho,
requestCode, onlyIfNeeded, debug, null, null);
}
//第五 ActivityStack.java
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);
...
return res;
}
// 第六 ActivityStack.java
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) {
...
//ActivityRecord构造方法中会创建一个token
ActivityRecord r = new ActivityRecord(mService, this, callerApp, callingUid,
intent, resolvedType, aInfo, mService.mConfiguration,
resultRecord, resultWho, requestCode, componentSpecified);
...
// 第八 其中r是想要启动的Activity组件对应的ActivityRecord对象
// sourceRecord是已经启动的Activity组件对应的ActivityRecord对象
err = startActivityUncheckedLocked(r, sourceRecord,grantedUriPermissions, grantedMode, onlyIfNeeded, true);
...
}
// 第七 ActivityRecord.java
ActivityRecord(ActivityManagerService _service, ActivityStack _stack, ProcessRecord _caller,
int _launchedFromUid, Intent _intent, String _resolvedType,
ActivityInfo aInfo, Configuration _configuration,
ActivityRecord _resultTo, String _resultWho, int _reqCode,
boolean _componentSpecified) {
...
// 该Token是一个binder本地对象,还在WMS中, 如何传入到Activity中的呢?
appToken = new Token(this);
...
}
//第八 ActivityStack.java中startActivityUncheckedLocked()
final int startActivityUncheckedLocked(ActivityRecord r,
ActivityRecord sourceRecord, Uri[] grantedUriPermissions,
int grantedMode, boolean onlyIfNeeded, boolean doResume) {
...
//上面还有一个 startActivityLocked(), 只是传入的参数不一样.
// 传入r 是目标ActivityRecord.
startActivityLocked(r, newTask, doResume, keepCurTransition);
return START_SUCCESS;
}
//第九 ActivityStack.java
private final void startActivityLocked(ActivityRecord r, boolean newTask,
boolean doResume, boolean keepCurTransition) {
...
mService.mWindowManager.addAppToken(addPos, r.appToken, r.task.taskId,
r.info.screenOrientation, r.fullscreen);
...
resumeTopActivityLocked(null);
...
}
//第十 ActivityStack.java
final boolean resumeTopActivityLocked(ActivityRecord prev) {
...
startPausingLocked(userLeaving, false);
}
// 第十一 ActivityStack.java
private final void startPausingLocked(boolean userLeaving, boolean uiSleeping) {
//被点击的Activity组件,已经启动显示在屏幕中.
ActivityRecord prev = mResumedActivity;
...
// 这里下一步就回到Client进程中了
// 注意:prev.appToken是已经启动了的APP的Token,不要弄混淆了,
prev.app.thread.schedulePauseActivity(prev.appToken, prev.finishing,userLeaving, prev.configChangeFlags);
}
// 第十二 ActivityThread.ApplicationThread.java
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);
}
// 第十三 ActivityThread.java
private void queueOrSendMessage(int what, Object obj, int arg1, int arg2) {
synchronized (this) {
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;
mH.sendMessage(msg);
}
}
// 第十四 ActivityThread.H.java
public void handleMessage(Message msg) {
...
case PAUSE_ACTIVITY:
handlePauseActivity((IBinder)msg.obj, false, msg.arg1 != 0, msg.arg2);
maybeSnapshot();
break;
...
}
//第十五 ActivityThread.java
private void handlePauseActivity(IBinder token, boolean finished,
boolean userLeaving, int configChanges) {
// 这里的token 是被点击的Activity组件,已经在屏幕中显示着,
// 现在是要让这个Activity暂停
//ActivityClientRecord 与WMS中的ActivityClient是一一对应关系,
ActivityClientRecord r = mActivities.get(token);
//暂停当前Activity
performPauseActivity(token, finished, r.isPreHoneycomb());
//从这里又跳到AMS中去了
ActivityManagerNative.getDefault().activityPaused(token);
}
//第十六 ActivityManagerService.java
public final void activityPaused(IBinder token) {
final long origId = Binder.clearCallingIdentity();
mMainStack.activityPaused(token, false);
Binder.restoreCallingIdentity(origId);
}
//第十七 ActivityStack.java
final void activityPaused(IBinder token, boolean timeout) {
...
completePauseLocked();
}
//第十八 ActivityStack.java
private final void completePauseLocked() {
ActivityRecord prev = mPausingActivity;
...
// prev 指的是当前已经被暂停后的Activity组件
resumeTopActivityLocked(prev);
}
//第十九 ActivityStack.java
final boolean resumeTopActivityLocked(ActivityRecord prev) {
//这里的next就是目标Activity组件对应的ActivityRecord对象
ActivityRecord next = topRunningActivityLocked(null);
startSpecificActivityLocked(next, true, true);
}
//第二十 ActivityStack.java
private final void startSpecificActivityLocked(ActivityRecord r,
boolean andResume, boolean checkConfig) {
//用目标Activity对应的ActivityRecord组件获取到目标APP进程
ProcessRecord app = mService.getProcessRecordLocked(r.processName,
r.info.applicationInfo.uid);
//此时目标APP进程肯定是存在的
if (app != null && app.thread != null) {
try {
app.addPackage(r.info.packageName);
//执行到此处继续往下看
realStartActivityLocked(r, app, andResume, checkConfig);
return;
} catch (RemoteException e) {
Slog.w(TAG, "Exception when starting activity "
+ r.intent.getComponent().flattenToShortString(), e);
}
}
}
//第二十一 ActivityStack.java
final boolean realStartActivityLocked(ActivityRecord r,
ProcessRecord app, boolean andResume, boolean checkConfig)
throws RemoteException {
// 到这里下一步就又回到了Client进程中去了,
// 注意r.appToken值,马上就结束Activity中token的探索旅程了.
app.thread.scheduleLaunchActivity(new Intent(r.intent), r.appToken,
System.identityHashCode(r), r.info,
new Configuration(mService.mConfiguration),
r.compat, r.icicle, results, newIntents, !andResume,
mService.isNextTransitionForward(), profileFile, profileFd,
profileAutoStop);
}
//第二十二 ActivityThread.java
public final void scheduleLaunchActivity(Intent intent, IBinder token, int ident,
ActivityInfo info, Configuration curConfig, CompatibilityInfo compatInfo,
Bundle state, List<ResultInfo> pendingResults,
List<Intent> pendingNewIntents, boolean notResumed, boolean isForward,
String profileName, ParcelFileDescriptor profileFd, boolean autoStopProfiler) {
ActivityClientRecord r = new ActivityClientRecord();
//将 AMS中ActivityRecord对象中的appToken,传到Client进程中来,存储到ActivityClientRecord中token变量中.
r.token = token;
...
// 将带有token的 ActivityClientRecord传递出去了
queueOrSendMessage(H.LAUNCH_ACTIVITY, r);
}
//第二十三 ActivityThread.java
private void queueOrSendMessage(int what, Object obj) {
queueOrSendMessage(what, obj, 0, 0);
}
//第二十四 ActivityThread.java
public void handleMessage(Message msg) {
switch (msg.what) {
case LAUNCH_ACTIVITY: {
ActivityClientRecord r = (ActivityClientRecord)msg.obj;
r.packageInfo = getPackageInfoNoCheck(
r.activityInfo.applicationInfo, r.compatInfo);
// 将带有token的 ActivityClientRecord传递出去了
handleLaunchActivity(r, null);
} break;
}
//第二十五 ActivityThread.java
private void handleLaunchActivity(ActivityClientRecord r, Intent customIntent) {
// 该方法是创建一个Activity对象
Activity a = performLaunchActivity(r, customIntent);
}
//第二十六 ActivityThread.java
private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
ActivityInfo aInfo = r.activityInfo;
java.lang.ClassLoader cl = r.packageInfo.getClassLoader();
//创建Activity
activity = mInstrumentation.newActivity(cl, component.getClassName(), r.intent);
//创建Application
Application app = r.packageInfo.makeApplication(false, mInstrumentation);
//看看这个关键的东西 r.token,这个就是当初在AMS中创建ActivityRecord对象时候创建的token对象了.
activity.attach(appContext, this, getInstrumentation(), r.token,r.ident, app, r.intent, r.activityInfo, title, r.parent,r.embeddedID, r.lastNonConfigurationInstances, config);
}
//第二十六 Activity.java
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) {
...
//这里终于Activity把token保存起来了.
mToken = token;
}
Window中的mAppToken
// Activity.java
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) {
attachBaseContext(context);
...
//TODO 第一步 创建PhoneWindow对象
mWindow = PolicyManager.makeNewWindow(this);
...
//TODO 第四步
mWindow.setWindowManager(null, mToken, mComponent.flattenToString(),
(info.flags & ActivityInfo.FLAG_HARDWARE_ACCELERATED) != 0);
// 题外话
// 可以看出来这个mParent也是从AMS传过来的
mParent = parent;
if (mParent != null) {
// 现在一般很少见到Activity中包含一个Activity,比如很早以前的`TabActivity`,现在都被`Fragment`替代了.
mWindow.setContainer(mParent.getWindow());
}
...
}
//TODO 第二步 PolicyManager.java
//private static final String POLICY_IMPL_CLASS_NAME = "com.android.internal.policy.impl.Policy";
public static Window makeNewWindow(Context context) {
//这个sPolicy对象需要看Policy.java类
return sPolicy.makeNewWindow(context);
}
//TODO 第三步 Policy.java
public Window makeNewWindow(Context context) {
//可以看到在attach()方法中创建Window最终得到一个PhoneWindow
//PhoneWindow 是Window唯一实现类
return new PhoneWindow(context);
}
//TODO 第四步 Window.java
//Window.setWindowManager()方法中传入的mToken就是Activity中的mToken,上面追了二十多步捋清楚它的来历.
public void setWindowManager(WindowManager wm, IBinder appToken, String appName,
boolean hardwareAccelerated) {
//看这里就知道了 Window中的mAppToken一般就是Activity中的mToken变量了.
mAppToken = appToken;
mAppName = appName;
if (wm == null) {
wm = WindowManagerImpl.getDefault();
}
mWindowManager = new LocalWindowManager(wm, hardwareAccelerated);
}
WindowManager.LayoutParams中的Token
- 当执行
Activity.java
中的attach()
时候,会创建WindowPhone
对象,此时会在Window
类中创建一个WindowManager.LayoutParams
的变量. - 当
Activity
准备好了会通知AMS,AMS最终经过各种条件判断最后调用到Activity
的makeVisible()
.
public class Activity extends ContextThemeWrapperimplements LayoutInflater.Factory,Window.Callback, KeyEvent.Callback,OnCreateContextMenuListener, ComponentCallbacks {
// TODO 第一步
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) {
...
// 调用setWindowManager()会创建WM对象.
mWindow.setWindowManager(null, mToken, mComponent.flattenToString(),
(info.flags & ActivityInfo.FLAG_HARDWARE_ACCELERATED) != 0);
...
// 获取LocalWindowManager对象
mWindowManager = mWindow.getWindowManager();
}
// TODO 第二步
// 等到Activity的一切工作准备完毕,现在就开始展示具体View了.
void makeVisible() {
if (!mWindowAdded) {
ViewManager wm = getWindowManager();
//通过LocalWindowManager对象执行addView()
wm.addView(mDecor, getWindow().getAttributes());
mWindowAdded = true;
}
mDecor.setVisibility(View.VISIBLE);
}
//获取Window.LocalWindowManager对象
public WindowManager getWindowManager() {
return mWindowManager;
}
}
//Window.java
public abstract class Window {
// 创建 mWindowAttributes变量
private final WindowManager.LayoutParams mWindowAttributes = new WindowManager.LayoutParams();
private class LocalWindowManager extends WindowManagerImpl.CompatModeWrapper {
// TODO 第三步
// view是上面传入的mDecor
// params是上面传入的WindowManager.LayoutParams对象.
public final void addView(View view, ViewGroup.LayoutParams params) {
WindowManager.LayoutParams wp = (WindowManager.LayoutParams)params;
//在创建WindowManager.LayoutParams对象的时候, 它默认是应用窗口.
//首先根据params的Type对象判断是否是子窗口
if (wp.type >= WindowManager.LayoutParams.FIRST_SUB_WINDOW &&
wp.type <= WindowManager.LayoutParams.LAST_SUB_WINDOW) {
//假如现在创建的是子窗口,且WindowManager.LayoutParams对象的token为空
if (wp.token == null) {
//peekDecorView()这个方法的具体实现是PhoneWindow中
//返回的就是PhoneWindow中的mDecor对象
View decor = peekDecorView();
if (decor != null) {
// 从这里可以知道,如果创建的是子窗口,当使用父窗口的LocalWindowManager对象添加子窗口的时候,
// 经过一系列判断最终会将父窗口中的decorView的token赋值给WindowManager.LayoutParams中的token变量.
// 这里是WindowManager.LayoutParams中的token由来的第一个情况
// 其实这里还有一个疑问, decorView中的token是如何来的呢?这个后面会分析.
// 先弄清楚WindowManager.LayoutParams中的token.
wp.token = decor.getWindowToken();
}
}
...
} else {
// 假如现在创建的不是子窗口,且WindowManager.LayoutParams对象的token为空
if (wp.token == null) {
// mContainer这个是表示父Activity.这里一般是没有父Activity的.
// 所以如果创建的不是子窗口,那么就将Activity中的token赋值给WindowManager.LayoutParams中的token.
// 到这里WindowManager.LayoutParams两种token的由来就说清楚了.
wp.token = mContainer == null ? mAppToken : mContainer.mAppToken;
}
...
}
...
}
}
//获取WindowManager.LayoutParams对象
public final WindowManager.LayoutParams getAttributes() {
return mWindowAttributes;
}
//创建WM对象
public void setWindowManager(WindowManager wm, IBinder appToken, String appName
boolean hardwareAccelerated) {
mAppToken = appToken;
mAppName = appName;
if (wm == null) {
wm = WindowManagerImpl.getDefault();
}
...
//getWindowManager()方法获取的就是LocalWindowManager
mWindowManager = new LocalWindowManager(wm, hardwareAccelerated);
}
}
//WindowManager.java
public interface WindowManager extends ViewManager {
public static class LayoutParams extends ViewGroup.LayoutParams implements Parcelable {
//在LayoutParams中,它有一个token变量, 现在就要找这个token是从哪儿来的.
public IBinder token = null;
//从这里可以看出mWindowAttributes对象的Type是一个应用窗口.
public LayoutParams() {
super(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);
type = TYPE_APPLICATION;
format = PixelFormat.OPAQUE;
}
}
}
View中的Token
- 探索WindowManager.LayoutParams中的Token的时候,如果是子窗体,那么WindowManager.LayoutParams中的Token是由decorView的token提供的.那decorView的token是怎么来的呢.
// Window.java
public abstract class Window {
private class LocalWindowManager extends WindowManagerImpl.CompatModeWrapper {
public final void addView(View view, ViewGroup.LayoutParams params) {
// TODO 第一步
//这一步会调用WindowManagerImpl.CompatModeWrapper中的addView()
super.addView(view, params);
}
}
}
// WindowManagerImpl.CompatModeWrapper.java
public class WindowManagerImpl implements WindowManager {
static class CompatModeWrapper implements WindowManager {
@Override
public void addView(View view, android.view.ViewGroup.LayoutParams params) {
// TODO 第二步
// 这里会调用WindowManagerImpl中的addView() 主要是这个方法
mWindowManager.addView(view, params, mCompatibilityInfo);
}
}
private void addView(View view, ViewGroup.LayoutParams params,CompatibilityInfoHolder cih, boolean nest) {
ViewRootImpl root;
//这个对象是在添加addView时候创建的
root = new ViewRootImpl(view.getContext());
...
// TODO 第三步
//继续向下看
root.setView(view, wparams, panelParentView);
}
}
//ViewRootImpl.java
//是ViewRootImpl还是ViewRoot影响不大
@SuppressWarnings({"EmptyCatchBlock", "PointlessBooleanExpression"})
public final class ViewRootImpl extends Handler implements ViewParent,View.AttachInfo.Callbacks, HardwareRenderer.HardwareDrawCallbacks {
final View.AttachInfo mAttachInfo;
final W mWindow;
public ViewRootImpl(Context context) {
// TODO 注意这里
//当ViewRootImpl对象被创建后,它内部的变量mAttachInfo也会自动被创建.
mWindow = new W(this);
//看AttachInfo构造方法可以知道,mWindow调用asBinder()得到的值最后赋值给AttachInfo中变量mWindowToken.
mAttachInfo = new View.AttachInfo(sWindowSession, mWindow, this, this);
}
public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView) {
synchronized (this) {
//这个mView就是需要新添加的View
mView = view;
...
// TODO 第四步
// 让窗口变得可见
requestLayout();
...
}
}
}
public void requestLayout() {
checkThread();
mLayoutRequested = true;
// TODO 第五步
//接着向下看
scheduleTraversals();
}
public void scheduleTraversals() {
if (!mTraversalScheduled) {
mTraversalScheduled = true;
// TODO 第六步
//接着向下看
sendEmptyMessage(DO_TRAVERSAL);
}
}
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
...
case DO_TRAVERSAL:
...
// TODO 第七步
performTraversals();
...
break;
}
private void performTraversals() {
//这个host就是需要新添加的View
final View host = mView;
// TODO 第八步
//接着往下看
host.dispatchAttachedToWindow(attachInfo, 0);
}
}
//View.java
public class View implements Drawable.Callback, KeyEvent.Callback, AccessibilityEventSource {
// TODO 第九步
void dispatchAttachedToWindow(AttachInfo info, int visibility) {
//这一步会将ViewRootImpl中的mAttachInfo变量传递到View中.
mAttachInfo = info;
...
}
// TODO 到这里就清楚了.
// 当ViewRootImp被创建后,会在它的构造方法中创建mAttachInfo对象, 这个对象中有一个mWindowToken变量.
// 在执行ViewRootImp.setView()的一系列方法调度之后,ViewRootImp中的变量mAttachInfo对象最终会传入到View对象中.
// 当在别的地方通过View调用getWindowToken()时候,获取的token就是在ViewRootImp构造中创建的.
public IBinder getWindowToken() {
return mAttachInfo != null ? mAttachInfo.mWindowToken : null;
}
// 这个构造方法在创建ViewRootImp对象时候被调用.
static class AttachInfo {
AttachInfo(IWindowSession session, IWindow window,Handler handler, Callbacks effectPlayer) {
mSession = session;
mWindow = window;
mWindowToken = window.asBinder();
mHandler = handler;
mRootCallbacks = effectPlayer;
}
}
}
至此,Activity中的token,Window中的mAppToken,WindowManager.LayoutParams中的Token,View中的mWindowToken都探索了一遍.