什么是Token?
Token是ActivityRecord静态内部类,继承于IApplicationToken.Stub,是AMS为了客户端新启动的Activity所创建,字面上理解它是具有代表Activity令牌的一个Binder。
这个Binder是AMS为Activity创建的一个唯一标识,AMS进程管理App进程的Activity的生命周期,所以用可以跨进程的Binder来标识Activity最合适不过。
Token创建?
AMS在创建启动Activity之前创建了ActivityRecord,ActivityRecord包含了待创建Activity所有的信息,并在构造函数中创建了Token,最终Activity创建好之后会得到它在客户端的本地Binder代理。
Token
Token继承IApplicationToken.Stub是一个Binder。1
2
3
4
5
6
7
8
9
10static 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();
}
...
}
Activity中的mToken
就是Token在客户端的本地Binder代理:1
2
3#Activity
private IBinder mToken;
创建ActivityRecord时同时创建了Token,保存在ActivityRecord中。
ActivityRecord:代表一个Activity的全部信息,在创建Activity时候被创建,里面维护被创建Activity的所有信息,包括所在进程、ActivityStack、所在应用、Activity状态、包名进程名、启动模式等。1
2
3
4
5
6
7
8
9
10
11ActivityRecord(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) {
...
appToken = new Token(this, _intent);
...
}
Token从创建到绑定到Activity的过程。
AMS收到客户端请求,调用startActivity(),经过多个方法的调用,进入ActivityStarter.startActivity()。1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19#ActivityStarter
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) {
...
//构造ActivityRecord
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,
checkedOptions, inTask, outActivity);
}
构造完ActivityRecord后,会调用startActivity()另一个重载函数,然后调用startActivityUnchecked()。1
2
3
4
5
6
7
8
9
10
11
12
13private int startActivityUnchecked(final ActivityRecord r, ActivityRecord sourceRecord,
IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor,
int startFlags, boolean doResume, ActivityOptions options, TaskRecord inTask,
ActivityRecord[] outActivity) {
...
mTargetStack.startActivityLocked(mStartActivity, topFocused, newTask, mKeepCurTransition,
mOptions);
...
mSupervisor.resumeFocusedStackTopActivityLocked(mTargetStack, mStartActivity,
mOptions);
...
return START_SUCCESS;
}
保存Token到mTokenMap
首先看mTargetStack.startActivityLocked(),这个方法的作用是使用Token构造AppWindowToken,然后保存到DisplayContent中的mTokenMap中,后面WMS添加Window时会和mTokenMap中的Token进行匹配验证。
DisplayContent.addWindowToken():1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18private void addWindowToken(IBinder binder, WindowToken token) {
final DisplayContent dc = mService.mRoot.getWindowTokenDisplay(token);
if (dc != null) {
throw new IllegalArgumentException("Can't map token=" + token + " to display="
+ getName() + " already mapped to display=" + dc + " tokens=" + dc.mTokenMap);
}
if (binder == null) {
throw new IllegalArgumentException("Can't map token=" + token + " to display="
+ getName() + " binder is null");
}
if (token == null) {
throw new IllegalArgumentException("Can't map null token to display="
+ getName() + " binder=" + binder);
}
mTokenMap.put(binder, token);
...
}
最后存储在DisplayContent的mTokenMap中,mTokenMap是IBinder和mTokenMap为键值对的HashMap,WMS添加Window时会通过mTokenMap来验证Token的合法性。
IPC传递Token到客户端
接着看resumeFocusedStackTopActivityLocked(),后面便是启动Activity的流程,经过ActivityStarter、ActivityStackSupervisor和ActivityStack的一系列跳转,
最后调用ActivityStackSupervisor.realStartActivityLocked(),向客户端发送创建和启动Activity的执行事务ClientTransaction。
其中app.thread
是客户端IApplicationThread的本地Binder代理,r.appToken
是ActivityRecord中保存的Token。1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23final boolean realStartActivityLocked(ActivityRecord r, ProcessRecord app,
boolean andResume, boolean checkConfig) throws RemoteException {
...
// 构造用于创建并启动Activity的事务。
// app.thread是IApplicationThread,r.appToken是ActivityRecord中保存的Token。
final ClientTransaction clientTransaction = ClientTransaction.obtain(app.thread,r.appToken);
clientTransaction.addCallback(LaunchActivityItem.obtain(new Intent(r.intent),
System.identityHashCode(r), r.info,mergedConfiguration.getGlobalConfiguration(),
mergedConfiguration.getOverrideConfiguration(), r.compat,r.launchedFromPackage,
task.voiceInteractor, app.repProcState, r.icicle,r.persistentState,
results, newIntents, mService.isNextTransitionForward(),profilerInfo));
final ActivityLifecycleItem lifecycleItem;
if (andResume) {
lifecycleItem = ResumeActivityItem.obtain(mService.isNextTransitionForward());
} else {
lifecycleItem = PauseActivityItem.obtain();
}
clientTransaction.setLifecycleStateRequest(lifecycleItem);
// 实行事务
mService.getLifecycleManager().scheduleTransaction(clientTransaction);
...
return true;
}
AMS.getLifecycleManager().scheduleTransaction()最终调用ClientTransaction.schedule()。1
2
3
4
5
6
7//ClientTransaction
private IApplicationThread mClient;
public void schedule() throws RemoteException {
mClient.scheduleTransaction(this);
}
接着调用客户端保存在AMS的IApplicationThread的本地代理,执行IPC,回到客户端scheduleTransaction()方法。1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22//ActivityThread.scheduleTransaction:
public void scheduleTransaction(ClientTransaction transaction) throws RemoteException {
ActivityThread.this.scheduleTransaction(transaction);
}
//ClientTransactionHandler.scheduleTransaction: 向ActivityThread.H发送message
void scheduleTransaction(ClientTransaction transaction) {
sendMessage(ActivityThread.H.EXECUTE_TRANSACTION, transaction);
}
//H.handleMessage:
public void handleMessage(Message msg) {
switch (msg.what) {
case EXECUTE_TRANSACTION:
final ClientTransaction transaction = (ClientTransaction) msg.obj;
mTransactionExecutor.execute(transaction);
break;
}
}
//TransactionExecutor.execute:
public void execute(ClientTransaction transaction) {
executeCallbacks(transaction);//执行LaunchActivityItem
executeLifecycleState(transaction);//执行ResumeActivityItem
}
继续看TransactionExecutor.executeCallbacks()。
transaction.getActivityToken()返回的Binder便是realStartActivityLocked()中保存的r.appToken
也就是ActivityRecord.Token,此时这个Binder经过IPC变成了客户端本地Binder代理。callbacks
中保存的便是realStartActivityLocked()中添加的LaunchActivityItem。1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24 public void executeCallbacks(ClientTransaction transaction) {
final List<ClientTransactionItem> callbacks = transaction.getCallbacks();
final IBinder token = transaction.getActivityToken();
...
final int size = callbacks.size();
for (int i = 0; i < size; ++i) {
final ClientTransactionItem item = callbacks.get(i);
item.execute(mTransactionHandler, token, mPendingActions);
...
}
}
//LaunchActivityItem.execute: 构造ActivityClientRecord,然后调用ActivityThread.handleLaunchActivity()。
public void execute(ClientTransactionHandler client, IBinder token,PendingTransactionActions pendingActions) {
ActivityClientRecord r = new ActivityClientRecord(token, mIntent, mIdent, mInfo,mOverrideConfig, mCompatInfo,
mReferrer,mVoiceInteractor,mState,mPersistentState,mPendingResults,mPendingNewIntents,mIsForward,mProfilerInfo,client);
client.handleLaunchActivity(r, pendingActions, null /* customIntent */);
}
//ActivityThread.handleLaunchActivity:
public Activity handleLaunchActivity(ActivityClientRecord r,PendingTransactionActions pendingActions,Intent customIntent){
...
final Activity a = performLaunchActivity(r, customIntent);
...
return a;
}
创建Activity并注入Token本地Binder引用
ActivityThread.performLaunchActivity()主要做了这么几件事:
- 为Activity构造上下文(ContextImpl);
- 通过Instrumentation反射构造Activity;
- 调用Activity.attach();
- 通过Instrumentation回调Activity的onCreate()。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
ActivityInfo aInfo = r.activityInfo;
...
//构造上下文
ContextImpl appContext = createBaseContextForActivity(r);
//创建Activity
Activity activity = null;
try {
java.lang.ClassLoader cl = appContext.getClassLoader();
activity = mInstrumentation.newActivity(
cl, component.getClassName(), r.intent);
r.intent.setExtrasClassLoader(cl);
r.intent.prepareToEnterProcess();
if (r.state != null) {
r.state.setClassLoader(cl);
}
} catch (Exception e) {
}
try {
Application app = r.packageInfo.makeApplication(false, mInstrumentation);
if (activity != null) {
CharSequence title = r.activityInfo.loadLabel(appContext.getPackageManager());
Configuration config = new Configuration(mCompatConfiguration);
if (r.overrideConfig != null) {
config.updateFrom(r.overrideConfig);
}
Window window = null;
if (r.mPendingRemoveWindow != null && r.mPreserveWindow) {
window = r.mPendingRemoveWindow;
r.mPendingRemoveWindow = null;
r.mPendingRemoveWindowManager = null;
}
appContext.setOuterContext(activity);
//为Activity添加变量
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 (customIntent != null) {
activity.mIntent = customIntent;
}
r.lastNonConfigurationInstances = null;
checkAndBlockForNetworkAccess();
activity.mStartedActivity = false;
int theme = r.activityInfo.getThemeResource();
if (theme != 0) {
activity.setTheme(theme);
}
activity.mCalled = false;
//回调Activity.onCreate()
if (r.isPersistable()) {
mInstrumentation.callActivityOnCreate(activity, r.state, r.persistentState);
} else {
mInstrumentation.callActivityOnCreate(activity, r.state);
}
r.activity = activity;
}
r.setState(ON_CREATE);
mActivities.put(r.token, r);
} catch (SuperNotCalledException e) {
throw e;
} catch (Exception e) {
}
return activity;
}
最后Token通过Activity.attach()绑定到Activity。1
2
3
4
5
6
7
8final 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) {
...
mToken = token;
...
}
简单概括
过程:AMS向App进程发起IPC,ActivityThread拿到Token在App进程的本地代理,创建好Activity后在attach()方法中注入到Activity中。
Token对于AMS和App的作用?
AMS端维护一份ProcessRecord数据结构,ProcessRecord代表一个进程的所有信息,包含了这个进程的TaskRecord和ActivityRecord和其他系统组件等。
App进程则在ActivityThread维护一个key和value为IBinder和ActivityClientRecord的ArrayMap,IBinder就是AMS端的那个Token,ActivityClientRecord则类似AMS端的ActivityRecord,存储着Activity实例和Activity相关信息。
这样,通过AMS还是App进程的ActivityThread均可以使用Token这个Binder查找到准确的Activity,然后进行相应操作。
应用场景:启动一个新的Activity:App携带Token本地Binder代理向AMS发起IPC,AMS准备创建并启动新的Activity,在新的Activity可见之前就会携带这个Token向App进程通信暂停上一个Activity,App进程收到通信后通过Token查找ActivityThread存储的列表,找到对应Activity后做相应处理并回调这个Activity的onPause(),然后AMS才会让新启动的Activity进入可见状态。
Token绑定到客户端Window的过程。
Token在Activity.attach()绑定到Activity中。1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56final 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(context);
mFragments.attachHost(null /*parent*/);
//构造PhoneWindow,当前Activity对应一个PhoneWindow简称PW。
mWindow = new PhoneWindow(this, window, activityConfigCallback);
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());
}
}
//第一个参数是WindowManagerImpl简称WMI,第二个是AMS端ActivityRecord为Activity生成的Token,这里是本地Binder代理
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();//返回PW构造的WMI对象。
mCurrentConfig = config;
mWindow.setColorMode(info.colorMode);
setAutofillCompatibilityEnabled(application.isAutofillCompatibilityEnabled());
enableAutofillCompatibilityIfNeeded();
}
mWindow.setWindowManager(): PW保存当前Activity的Token,然后WMI.createLocalWindowManager(PW)构造WMI保存在PW中。1
2
3
4
5
6
7
8
9public void setWindowManager(WindowManager wm, IBinder appToken, String appName, boolean hardwareAccelerated){
mAppToken = appToken;
mAppName = appName;
mHardwareAccelerated = hardwareAccelerated || SystemProperties.getBoolean(PROPERTY_HARDWARE_UI, false);
if (wm == null) {
wm = (WindowManager)mContext.getSystemService(Context.WINDOW_SERVICE);
}
mWindowManager = ((WindowManagerImpl)wm).createLocalWindowManager(this);
}
设置内容视图
调用attach()后,在onCreate()中调用setContentView()完成布局视图的添加,这里以setContentView(View view)简化说明。
常用的setContentView(int layoutResID)内部调用mLayoutInflater.inflate(layoutResID, mContentParent)。1
2
3
4public void setContentView(View view) {
getWindow().setContentView(view);
initWindowDecorActionBar();
}
getWindow()返回PW,看PW.setContentView(view)1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26public void setContentView(View view) {
setContentView(view, new ViewGroup.LayoutParams(MATCH_PARENT, MATCH_PARENT));
}
public void setContentView(View view, ViewGroup.LayoutParams params) {
if (mContentParent == null) {
installDecor();
} else if (!hasFeature(FEATURE_CONTENT_TRANSITIONS)) {
mContentParent.removeAllViews();
}
if (hasFeature(FEATURE_CONTENT_TRANSITIONS)) {
view.setLayoutParams(params);
final Scene newScene = new Scene(mContentParent, view);
transitionTo(newScene);
} else {
//setContentView(int layoutResID)调用mLayoutInflater.inflate(layoutResID, mContentParent)。
//最后也调用mContentParent.addView(view, params)。
mContentParent.addView(view, params);
}
mContentParent.requestApplyInsets();
final Callback cb = getCallback();
if (cb != null && !isDestroyed()) {
cb.onContentChanged();
}
mContentParentExplicitlySet = true;
}
mContentParent在setContentView()被调用前是null,先执行installDecor()。1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18private void installDecor() {
mForceDecorInstall = false;
if (mDecor == null) {
mDecor = generateDecor(-1);
mDecor.setDescendantFocusability(ViewGroup.FOCUS_AFTER_DESCENDANTS);
mDecor.setIsRootNamespace(true);
if (!mInvalidatePanelMenuPosted && mInvalidatePanelMenuFeatures != 0) {
mDecor.postOnAnimation(mInvalidatePanelMenuRunnable);
}
} else {
mDecor.setWindow(this);
}
if (mContentParent == null) {
mContentParent = generateLayout(mDecor);
...
}
}
mDecor是DecorView,是一个FrameLayout,理解为Activity的根布局。generateDecor(-1)构造DecorView。
mContentParent是DecorView的子View中id为R.id.content
的View。1
2
3
4
5
6
7protected ViewGroup generateLayout(DecorView decor) {
...
ViewGroup contentParent = (ViewGroup)findViewById(ID_ANDROID_CONTENT);
...
return contentParent;
}
public static final int ID_ANDROID_CONTENT = com.android.internal.R.id.content;
最后调用mContentParent.addView(view, params),再理解setContentView()方法名的含义便恍然大悟了,用户只是把布局添加到了id为R.id.content
的mContentParent上面而已,因为mContentParent上面还有XxxBar之类的布局。
展示视图
ActivityThread.handleResumeActivity():1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81public void handleResumeActivity(IBinder token, boolean finalStateRequest, boolean isForward, String reason){
unscheduleGcIdler();
mSomeActivitiesChanged = true;
final ActivityClientRecord r = performResumeActivity(token, finalStateRequest, reason);
if (r == null) {
return;
}
final Activity a = r.activity;
final int forwardBit = isForward ? WindowManager.LayoutParams.SOFT_INPUT_IS_FORWARD_NAVIGATION : 0;
boolean willBeVisible = !a.mStartedActivity;
if (!willBeVisible) {
try {
willBeVisible = ActivityManager.getService().willActivityBeVisible(a.getActivityToken());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
if (r.window == null && !a.mFinished && willBeVisible) {
r.window = r.activity.getWindow();
View decor = r.window.getDecorView();
decor.setVisibility(View.INVISIBLE);
ViewManager wm = a.getWindowManager();
WindowManager.LayoutParams l = r.window.getAttributes();
a.mDecor = decor;
l.type = WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
l.softInputMode |= forwardBit;
if (r.mPreserveWindow) {
a.mWindowAdded = true;
r.mPreserveWindow = false;
ViewRootImpl impl = decor.getViewRootImpl();
if (impl != null) {
impl.notifyChildRebuilt();
}
}
if (a.mVisibleFromClient) {
if (!a.mWindowAdded) {
a.mWindowAdded = true;
wm.addView(decor, l);
} else {
a.onWindowAttributesChanged(l);
}
}
} else if (!willBeVisible) {
r.hideForNow = true;
}
cleanUpPendingRemoveWindows(r, false /* force */);
if (!r.activity.mFinished && willBeVisible && r.activity.mDecor != null && !r.hideForNow) {
if (r.newConfig != null) {
performConfigurationChangedForActivity(r, r.newConfig);
r.newConfig = null;
}
WindowManager.LayoutParams l = r.window.getAttributes();
if ((l.softInputMode & WindowManager.LayoutParams.SOFT_INPUT_IS_FORWARD_NAVIGATION)
!= forwardBit) {
l.softInputMode = (l.softInputMode
& (~WindowManager.LayoutParams.SOFT_INPUT_IS_FORWARD_NAVIGATION))
| forwardBit;
if (r.activity.mVisibleFromClient) {
ViewManager wm = a.getWindowManager();
View decor = r.window.getDecorView();
wm.updateViewLayout(decor, l);
}
}
r.activity.mVisibleFromServer = true;
mNumVisibleActivities++;
if (r.activity.mVisibleFromClient) {
r.activity.makeVisible();
}
}
r.nextIdle = mNewActivities;
mNewActivities = r;
Looper.myQueue().addIdleHandler(new Idler());
}
调用performResumeActivity()依次完成Activity的onRestart()、onStart()、onResume()回调;
把PW中的DecorView视图状态设置为INVISIBLE;
调用wm.addView(decor, l)添加视图,其中wm是WMI,在attach()中,把PW构造的WMI对象赋给Activity;
调用r.activity.makeVisible()设置页面View为可见。
通知WMS添加视图窗口
WMS.addView(decor, l):1
2
3
4
5
6public void addView(@NonNull View view, @NonNull ViewGroup.LayoutParams params) {
applyDefaultToken(params);
mGlobal.addView(view, params, mContext.getDisplay(), mParentWindow);
}
WindowManagerGlobal维护一个进程单例。
private final WindowManagerGlobal mGlobal = WindowManagerGlobal.getInstance();
WindowManagerGlobal.addView()做了4件事。
1,调用PW.adjustLayoutParamsForSubWindow()为WindowManager.LayoutParams绑定Token;
2,构造ViewRootImpl(简称VRI);
3,为DecorView设置WindowManager.LayoutParams;
4,把DecorView、VRI和WindowManager.LayoutParams添加到WMG中的List中缓存起来;
5,调用root.setView(view, wparams, panelParentView)做进一步设置;1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44public void addView(View view, ViewGroup.LayoutParams params, Display display, Window parentWindow) {
if (view == null) {
throw new IllegalArgumentException("view must not be null");
}
if (display == null) {
throw new IllegalArgumentException("display must not be null");
}
if (!(params instanceof WindowManager.LayoutParams)) {
throw new IllegalArgumentException("Params must be WindowManager.LayoutParams");
}
final WindowManager.LayoutParams wparams = (WindowManager.LayoutParams) params;
if (parentWindow != null) {
parentWindow.adjustLayoutParamsForSubWindow(wparams);
} else {
final Context context = view.getContext();
if (context != null
&& (context.getApplicationInfo().flags
& ApplicationInfo.FLAG_HARDWARE_ACCELERATED) != 0) {
wparams.flags |= WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED;
}
}
ViewRootImpl root;
View panelParentView = null;
synchronized (mLock) {
...
root = new ViewRootImpl(view.getContext(), display);
view.setLayoutParams(wparams);
mViews.add(view);
mRoots.add(root);
mParams.add(wparams);
try {
root.setView(view, wparams, panelParentView);
} catch (RuntimeException e) {
if (index >= 0) { removeViewLocked(index, true); }
throw e;
}
}
}
4.1 先看parentWindow.adjustLayoutParamsForSubWindow(),parentWindow是PW,创建WMI时注入到WMI中的,这个方法在PW的父类Window中。1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57void adjustLayoutParamsForSubWindow(WindowManager.LayoutParams wp) {
CharSequence curTitle = wp.getTitle();
if (wp.type >= WindowManager.LayoutParams.FIRST_SUB_WINDOW &&
wp.type <= WindowManager.LayoutParams.LAST_SUB_WINDOW) {
if (wp.token == null) {
View decor = peekDecorView();
if (decor != null) {
wp.token = decor.getWindowToken();
}
}
if (curTitle == null || curTitle.length() == 0) {
final StringBuilder title = new StringBuilder(32);
if (wp.type == WindowManager.LayoutParams.TYPE_APPLICATION_MEDIA) {
title.append("Media");
} else if (wp.type == WindowManager.LayoutParams.TYPE_APPLICATION_MEDIA_OVERLAY) {
title.append("MediaOvr");
} else if (wp.type == WindowManager.LayoutParams.TYPE_APPLICATION_PANEL) {
title.append("Panel");
} else if (wp.type == WindowManager.LayoutParams.TYPE_APPLICATION_SUB_PANEL) {
title.append("SubPanel");
} else if (wp.type == WindowManager.LayoutParams.TYPE_APPLICATION_ABOVE_SUB_PANEL) {
title.append("AboveSubPanel");
} else if (wp.type == WindowManager.LayoutParams.TYPE_APPLICATION_ATTACHED_DIALOG) {
title.append("AtchDlg");
} else {
title.append(wp.type);
}
if (mAppName != null) {
title.append(":").append(mAppName);
}
wp.setTitle(title);
}
} else if (wp.type >= WindowManager.LayoutParams.FIRST_SYSTEM_WINDOW &&
wp.type <= WindowManager.LayoutParams.LAST_SYSTEM_WINDOW) {
if (curTitle == null || curTitle.length() == 0) {
final StringBuilder title = new StringBuilder(32);
title.append("Sys").append(wp.type);
if (mAppName != null) {
title.append(":").append(mAppName);
}
wp.setTitle(title);
}
} else {
if (wp.token == null) {
wp.token = mContainer == null ? mAppToken : mContainer.mAppToken;
}
if ((curTitle == null || curTitle.length() == 0) && mAppName != null) {
wp.setTitle(mAppName);
}
}
if (wp.packageName == null) {
wp.packageName = mContext.getPackageName();
}
if (mHardwareAccelerated || (mWindowAttributes.flags & FLAG_HARDWARE_ACCELERATED) != 0) {
wp.flags |= FLAG_HARDWARE_ACCELERATED;
}
}
这个方法把Activity的Token拿来给WindowManager.LayoutParams中的token赋值,这样Token从PW绑定到了WindowManager.LayoutParams。
4.2 构造ViewRootImpl实例1
2
3
4
5public ViewRootImpl(Context context, Display display) {
...
mWindowSession = WindowManagerGlobal.getWindowSession();
...
}
ViewRootImpl构造了1个关键的变量:mWindowSession。mWindowSession是Session,存在于SystemServer进程中。
每个进程对应一个Session,WMG维护一个Session单例。
首先WMG获取WMS在客户端的本地Binder代理,然后用WMS本地代理获取Session,WMS端构造Session后把Session返回给客户端,客户端拿到了Session的本地Binder代理。1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50//WMG
public static IWindowSession getWindowSession() {
synchronized (WindowManagerGlobal.class) {
if (sWindowSession == null) {
try {
InputMethodManager imm = InputMethodManager.getInstance();
IWindowManager windowManager = getWindowManagerService();
sWindowSession = windowManager.openSession(
new IWindowSessionCallback.Stub() {
public void onAnimatorScaleChanged(float scale) {
ValueAnimator.setDurationScale(scale);
}
},
imm.getClient(), imm.getInputContext());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
return sWindowSession;
}
}
//WMG
public static IWindowManager getWindowManagerService() {
synchronized (WindowManagerGlobal.class) {
if (sWindowManagerService == null) {
sWindowManagerService = IWindowManager.Stub.asInterface(
ServiceManager.getService("window"));
try {
if (sWindowManagerService != null) {
ValueAnimator.setDurationScale(
sWindowManagerService.getCurrentAnimatorScale());
}
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
return sWindowManagerService;
}
}
//WMS
public IWindowSession openSession(IWindowSessionCallback callback, IInputMethodClient client,
IInputContext inputContext) {
if (client == null) throw new IllegalArgumentException("null client");
if (inputContext == null) throw new IllegalArgumentException("null inputContext");
Session session = new Session(this, callback, client, inputContext);
return session;
}
//Session
class Session extends IWindowSession.Stub implements IBinder.DeathRecipient
4.4 VRI向Session发起IPC,并把自己设置为DecorView的ViewParent。1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView) {
synchronized (this) {
if (mView == null) {
mView = view;
...
try {
mOrigWindowType = mWindowAttributes.type;
mAttachInfo.mRecomputeGlobalAttributes = true;
collectViewAttributes();
res = mWindowSession.addToDisplay(mWindow, mSeq, mWindowAttributes,
getHostVisibility(), mDisplay.getDisplayId(), mWinFrame,
mAttachInfo.mContentInsets, mAttachInfo.mStableInsets,
mAttachInfo.mOutsets, mAttachInfo.mDisplayCutout, mInputChannel);
} catch (RemoteException e) {
mAdded = false;
mView = null;
mAttachInfo.mRootView = null;
mInputChannel = null;
mFallbackEventHandler.setView(null);
unscheduleTraversals();
setAccessibilityFocus(null, null);
throw new RuntimeException("Adding window failed", e);
} finally {
if (restore) {
attrs.restore();
}
}
//把VRI绑定到DecorView。
view.assignParent(this);
...
}
}
}
mWindowSession.addToDisplay():1
2
3
4
5
6public int addToDisplay(IWindow window, int seq, WindowManager.LayoutParams attrs, int viewVisibility,
int displayId, Rect outFrame, Rect outContentInsets, Rect outStableInsets, Rect outOutsets,
DisplayCutout.ParcelableWrapper outDisplayCutout, InputChannel outInputChannel) {
return mService.addWindow(this, window, seq, attrs, viewVisibility, displayId, outFrame,
outContentInsets, outStableInsets, outOutsets, outDisplayCutout, outInputChannel);
}
mService就是WMS,WMS.addWindow():1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297public int addWindow(Session session, IWindow client, int seq,
LayoutParams attrs, int viewVisibility, int displayId, Rect outFrame,
Rect outContentInsets, Rect outStableInsets, Rect outOutsets,
DisplayCutout.ParcelableWrapper outDisplayCutout, InputChannel outInputChannel) {
int[] appOp = new int[1];
int res = mPolicy.checkAddPermission(attrs, appOp);
if (res != WindowManagerGlobal.ADD_OKAY) {
return res;
}
boolean reportNewConfig = false;
WindowState parentWindow = null;
long origId;
final int callingUid = Binder.getCallingUid();
final int type = attrs.type;
synchronized(mWindowMap) {
if (!mDisplayReady) {
throw new IllegalStateException("Display has not been initialialized");
}
final DisplayContent displayContent = getDisplayContentOrCreate(displayId);
if (displayContent == null) {
return WindowManagerGlobal.ADD_INVALID_DISPLAY;
}
if (!displayContent.hasAccess(session.mUid)
&& !mDisplayManagerInternal.isUidPresentOnDisplay(session.mUid, displayId)) {
return WindowManagerGlobal.ADD_INVALID_DISPLAY;
}
if (mWindowMap.containsKey(client.asBinder())) {
return WindowManagerGlobal.ADD_DUPLICATE_ADD;
}
if (type >= FIRST_SUB_WINDOW && type <= LAST_SUB_WINDOW) {
parentWindow = windowForClientLocked(null, attrs.token, false);
if (parentWindow == null) {
return WindowManagerGlobal.ADD_BAD_SUBWINDOW_TOKEN;
}
if (parentWindow.mAttrs.type >= FIRST_SUB_WINDOW
&& parentWindow.mAttrs.type <= LAST_SUB_WINDOW) {
return WindowManagerGlobal.ADD_BAD_SUBWINDOW_TOKEN;
}
}
if (type == TYPE_PRIVATE_PRESENTATION && !displayContent.isPrivate()) {
return WindowManagerGlobal.ADD_PERMISSION_DENIED;
}
AppWindowToken atoken = null;
final boolean hasParent = parentWindow != null;
WindowToken token = displayContent.getWindowToken(
hasParent ? parentWindow.mAttrs.token : attrs.token);
final int rootType = hasParent ? parentWindow.mAttrs.type : type;
boolean addToastWindowRequiresToken = false;
if (token == null) {
if (rootType >= FIRST_APPLICATION_WINDOW && rootType <= LAST_APPLICATION_WINDOW) {
return WindowManagerGlobal.ADD_BAD_APP_TOKEN;
}
if (rootType == TYPE_INPUT_METHOD) {
return WindowManagerGlobal.ADD_BAD_APP_TOKEN;
}
if (rootType == TYPE_VOICE_INTERACTION) {
return WindowManagerGlobal.ADD_BAD_APP_TOKEN;
}
if (rootType == TYPE_WALLPAPER) {
return WindowManagerGlobal.ADD_BAD_APP_TOKEN;
}
if (rootType == TYPE_DREAM) {
return WindowManagerGlobal.ADD_BAD_APP_TOKEN;
}
if (rootType == TYPE_QS_DIALOG) {
return WindowManagerGlobal.ADD_BAD_APP_TOKEN;
}
if (rootType == TYPE_ACCESSIBILITY_OVERLAY) {
return WindowManagerGlobal.ADD_BAD_APP_TOKEN;
}
if (type == TYPE_TOAST) {
if (doesAddToastWindowRequireToken(attrs.packageName, callingUid,
parentWindow)) {
return WindowManagerGlobal.ADD_BAD_APP_TOKEN;
}
}
final IBinder binder = attrs.token != null ? attrs.token : client.asBinder();
final boolean isRoundedCornerOverlay =
(attrs.privateFlags & PRIVATE_FLAG_IS_ROUNDED_CORNERS_OVERLAY) != 0;
token = new WindowToken(this, binder, type, false, displayContent,
session.mCanAddInternalSystemWindow, isRoundedCornerOverlay);
} else if (rootType >= FIRST_APPLICATION_WINDOW && rootType <= LAST_APPLICATION_WINDOW) {
atoken = token.asAppWindowToken();
if (atoken == null) {
return WindowManagerGlobal.ADD_NOT_APP_TOKEN;
} else if (atoken.removed) {
return WindowManagerGlobal.ADD_APP_EXITING;
} else if (type == TYPE_APPLICATION_STARTING && atoken.startingWindow != null) {
return WindowManagerGlobal.ADD_DUPLICATE_ADD;
}
} else if (rootType == TYPE_INPUT_METHOD) {
if (token.windowType != TYPE_INPUT_METHOD) {
return WindowManagerGlobal.ADD_BAD_APP_TOKEN;
}
} else if (rootType == TYPE_VOICE_INTERACTION) {
if (token.windowType != TYPE_VOICE_INTERACTION) {
return WindowManagerGlobal.ADD_BAD_APP_TOKEN;
}
} else if (rootType == TYPE_WALLPAPER) {
if (token.windowType != TYPE_WALLPAPER) {
return WindowManagerGlobal.ADD_BAD_APP_TOKEN;
}
} else if (rootType == TYPE_DREAM) {
if (token.windowType != TYPE_DREAM) {
return WindowManagerGlobal.ADD_BAD_APP_TOKEN;
}
} else if (rootType == TYPE_ACCESSIBILITY_OVERLAY) {
if (token.windowType != TYPE_ACCESSIBILITY_OVERLAY) {
return WindowManagerGlobal.ADD_BAD_APP_TOKEN;
}
} else if (type == TYPE_TOAST) {
addToastWindowRequiresToken = doesAddToastWindowRequireToken(attrs.packageName,
callingUid, parentWindow);
if (addToastWindowRequiresToken && token.windowType != TYPE_TOAST) {
return WindowManagerGlobal.ADD_BAD_APP_TOKEN;
}
} else if (type == TYPE_QS_DIALOG) {
if (token.windowType != TYPE_QS_DIALOG) {
return WindowManagerGlobal.ADD_BAD_APP_TOKEN;
}
} else if (token.asAppWindowToken() != null) {
attrs.token = null;
token = new WindowToken(this, client.asBinder(), type, false, displayContent,
session.mCanAddInternalSystemWindow);
}
final WindowState win = new WindowState(this, session, client, token, parentWindow,
appOp[0], seq, attrs, viewVisibility, session.mUid,
session.mCanAddInternalSystemWindow);
if (win.mDeathRecipient == null) {
return WindowManagerGlobal.ADD_APP_EXITING;
}
if (win.getDisplayContent() == null) {
return WindowManagerGlobal.ADD_INVALID_DISPLAY;
}
final boolean hasStatusBarServicePermission =
mContext.checkCallingOrSelfPermission(permission.STATUS_BAR_SERVICE)
== PackageManager.PERMISSION_GRANTED;
mPolicy.adjustWindowParamsLw(win, win.mAttrs, hasStatusBarServicePermission);
win.setShowToOwnerOnlyLocked(mPolicy.checkShowToOwnerOnly(attrs));
res = mPolicy.prepareAddWindowLw(win, attrs);
if (res != WindowManagerGlobal.ADD_OKAY) {
return res;
}
final boolean openInputChannels = (outInputChannel != null
&& (attrs.inputFeatures & INPUT_FEATURE_NO_INPUT_CHANNEL) == 0);
if (openInputChannels) {
win.openInputChannel(outInputChannel);
}
if (type == TYPE_TOAST) {
if (!getDefaultDisplayContentLocked().canAddToastWindowForUid(callingUid)) {
return WindowManagerGlobal.ADD_DUPLICATE_ADD;
}
if (addToastWindowRequiresToken
|| (attrs.flags & LayoutParams.FLAG_NOT_FOCUSABLE) == 0
|| mCurrentFocus == null
|| mCurrentFocus.mOwnerUid != callingUid) {
mH.sendMessageDelayed(mH.obtainMessage(H.WINDOW_HIDE_TIMEOUT, win),
win.mAttrs.hideTimeoutMilliseconds);
}
}
// From now on, no exceptions or errors allowed!
res = WindowManagerGlobal.ADD_OKAY;
if (mCurrentFocus == null) {
mWinAddedSinceNullFocus.add(win);
}
if (excludeWindowTypeFromTapOutTask(type)) {
displayContent.mTapExcludedWindows.add(win);
}
origId = Binder.clearCallingIdentity();
win.attach();
mWindowMap.put(client.asBinder(), win);
win.initAppOpsState();
final boolean suspended = mPmInternal.isPackageSuspended(win.getOwningPackage(),
UserHandle.getUserId(win.getOwningUid()));
win.setHiddenWhileSuspended(suspended);
final boolean hideSystemAlertWindows = !mHidingNonSystemOverlayWindows.isEmpty();
win.setForceHideNonSystemOverlayWindowIfNeeded(hideSystemAlertWindows);
final AppWindowToken aToken = token.asAppWindowToken();
if (type == TYPE_APPLICATION_STARTING && aToken != null) {
aToken.startingWindow = win;
}
boolean imMayMove = true;
win.mToken.addWindow(win);
if (type == TYPE_INPUT_METHOD) {
win.mGivenInsetsPending = true;
setInputMethodWindowLocked(win);
imMayMove = false;
} else if (type == TYPE_INPUT_METHOD_DIALOG) {
displayContent.computeImeTarget(true /* updateImeTarget */);
imMayMove = false;
} else {
if (type == TYPE_WALLPAPER) {
displayContent.mWallpaperController.clearLastWallpaperTimeoutTime();
displayContent.pendingLayoutChanges |= FINISH_LAYOUT_REDO_WALLPAPER;
} else if ((attrs.flags&FLAG_SHOW_WALLPAPER) != 0) {
displayContent.pendingLayoutChanges |= FINISH_LAYOUT_REDO_WALLPAPER;
} else if (displayContent.mWallpaperController.isBelowWallpaperTarget(win)) {
displayContent.pendingLayoutChanges |= FINISH_LAYOUT_REDO_WALLPAPER;
}
}
win.applyAdjustForImeIfNeeded();
if (type == TYPE_DOCK_DIVIDER) {
mRoot.getDisplayContent(displayId).getDockedDividerController().setWindow(win);
}
final WindowStateAnimator winAnimator = win.mWinAnimator;
winAnimator.mEnterAnimationPending = true;
winAnimator.mEnteringAnimation = true;
if (atoken != null && atoken.isVisible()
&& !prepareWindowReplacementTransition(atoken)) {
prepareNoneTransitionForRelaunching(atoken);
}
final DisplayFrames displayFrames = displayContent.mDisplayFrames;
final DisplayInfo displayInfo = displayContent.getDisplayInfo();
displayFrames.onDisplayInfoUpdated(displayInfo,
displayContent.calculateDisplayCutoutForRotation(displayInfo.rotation));
final Rect taskBounds;
if (atoken != null && atoken.getTask() != null) {
taskBounds = mTmpRect;
atoken.getTask().getBounds(mTmpRect);
} else {
taskBounds = null;
}
if (mPolicy.getLayoutHintLw(win.mAttrs, taskBounds, displayFrames, outFrame,
outContentInsets, outStableInsets, outOutsets, outDisplayCutout)) {
res |= WindowManagerGlobal.ADD_FLAG_ALWAYS_CONSUME_NAV_BAR;
}
if (mInTouchMode) {
res |= WindowManagerGlobal.ADD_FLAG_IN_TOUCH_MODE;
}
if (win.mAppToken == null || !win.mAppToken.isClientHidden()) {
res |= WindowManagerGlobal.ADD_FLAG_APP_VISIBLE;
}
mInputMonitor.setUpdateInputWindowsNeededLw();
boolean focusChanged = false;
if (win.canReceiveKeys()) {
focusChanged = updateFocusedWindowLocked(UPDATE_FOCUS_WILL_ASSIGN_LAYERS,
false /*updateInputWindows*/);
if (focusChanged) {
imMayMove = false;
}
}
if (imMayMove) {
displayContent.computeImeTarget(true /* updateImeTarget */);
}
win.getParent().assignChildLayers();
if (focusChanged) {
mInputMonitor.setInputFocusLw(mCurrentFocus, false /*updateInputWindows*/);
}
mInputMonitor.updateInputWindowsLw(false /*force*/);
if (win.isVisibleOrAdding() && updateOrientationFromAppTokensLocked(displayId)) {
reportNewConfig = true;
}
}
if (reportNewConfig) {
sendNewConfiguration(displayId);
}
Binder.restoreCallingIdentity(origId);
return res;
}
WindowManager.LayoutParams的Type
WindowManager.LayoutParams的type有3种主要类型:
1,ApplicationWindows: 取值在 FIRST_APPLICATION_WINDOW 和 LAST_APPLICATION_WINDOW 之间。是通常的、顶层的应用程序窗口。必须将token设置成Activity的token。如Activity,Dialog。
2,SubWindows: 取值在 FIRST_SUB_WINDOW 和 LAST_SUB_WINDOW 之间。token必须设置为它所附着的宿主窗口的token。如PopupWindow(想要依附在Activity上需要将token设置成Activity的token)。
3,SystemWindows: 取值在 FIRST_SYSTEM_WINDOW 和 LAST_SYSTEM_WINDOW 之间。用于特定的系统功能,不能用于应用程序,使用时需要特殊权限。如Toast,输入法等。
client是VRI静态内部类W,是一个Binder,WMS这边拿到的是它的本地Binder代理;attrs.token是Token。
首先检测mWindowMap用于是否重复添加视图;
然后判断type,在不是SubWindow情况下调用DisplayContent.getWindowToken(attrs.token),从mTokenMap获取WindowToken以及AppWindowToken来配合WindowManager.LayoutParams.type做一些合法性的判断,如果Token不合法则返回相应错误码。
最后均合法的话使用Session、client、attrs等参数构造WindowState,然后使用VRI.W这个Binder为key和WindowState为value存进mWindowMap中。mWindowMap缓存了这些参数,提供Window的添加删除等操作。
简单概括
过程:Activity通过PhoneWindow把Token放到DecorView的WindowManager.LayoutParams中。然后App进程向WMS发起IPC,WMS拿到Token保存到WindowState,最终存储到WMS的mWindowMap
中。
Token对于WMS的作用?
Activity在创建Token后,在ActivityStarter.startActivityLocked()方法中创建WindowToken,然后以Token和WindowToken为键值存储在DisplayContent的mTokenMap
中(点击查看)。当WMS调用addWindow添加Window时候,会使用Activity传过来的Token去mTokenMap
查找,来验证Token的合法性。