接著上篇:http://www.itdecent.cn/p/67a61225fdc7?v=1698053234018
三、代碼流程詳解
1.客戶端
1.1 Activity走到onresume后
從ActivityThread.handleResumeActivity方法看起
1.調(diào)用performResumeActivity,執(zhí)行onResume。
2.獲取WindowManager的實(shí)現(xiàn)類WindowManagerImpl的實(shí)例。
3.調(diào)用WindowManagerImpl.addView傳入DecorView和當(dāng)前布局參數(shù)WindowManager.LayoutParams。
代碼路徑:framework/core/java/android/app/ActivityThread.java
@Override
public void handleResumeActivity(ActivityClientRecord r, boolean finalStateRequest,
boolean isForward, String reason) {
......
// TODO Push resumeArgs into the activity for consideration
// skip below steps for double-resume and r.mFinish = true case.
/*1.執(zhí)行onResume*/
if (!performResumeActivity(r, finalStateRequest, reason)) {
return;
}
......
//獲取Activity實(shí)例
final Activity a = r.activity;
......
// If the window hasn't yet been added to the window manager,
// and this guy didn't finish itself or start another activity,
// then go ahead and add the window.
//mStartedActivity在performLaunchActivity和performResumeActivity方法中被置為false
boolean willBeVisible = !a.mStartedActivity;
......
if (r.window == null && !a.mFinished && willBeVisible) {
//獲取當(dāng)前Activity的PhoneWindow
r.window = r.activity.getWindow();
//從PhoneWindow中獲取DecorView
View decor = r.window.getDecorView();
//將view的可見性狀態(tài)設(shè)置為INVISIBLE,view不可見但是仍然占用布局空間
decor.setVisibility(View.INVISIBLE);
/*2.獲取WindowManager的實(shí)現(xiàn)類WindowManagerImpl的實(shí)例*/
ViewManager wm = a.getWindowManager();
//獲取布局參數(shù)
WindowManager.LayoutParams l = r.window.getAttributes();
//將phoneWindow的DecorView賦值給mDecor
a.mDecor = decor;
//設(shè)置窗口類型為TYPE_BASE_APPLICATION
l.type = WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
l.softInputMode |= forwardBit;
if (r.mPreserveWindow) {
a.mWindowAdded = true;
r.mPreserveWindow = false;
// Normally the ViewRoot sets up callbacks with the Activity
// in addView->ViewRootImpl#setView. If we are instead reusing
// the decor view we have to notify the view root that the
// callbacks may have changed.
ViewRootImpl impl = decor.getViewRootImpl();
if (impl != null) {
impl.notifyChildRebuilt();
}
}
if (a.mVisibleFromClient) {
if (!a.mWindowAdded) {
a.mWindowAdded = true;
/*3.傳入DecorView和當(dāng)前布局參數(shù)WindowManager.LayoutParams*/
wm.addView(decor, l);
} else {
// The activity will get a callback for this {@link LayoutParams} change
// earlier. However, at that time the decor will not be set (this is set
// in this method), so no action will be taken. This call ensures the
// callback occurs with the decor set.
a.onWindowAttributesChanged(l);
}
}
}
......
}
wm.addView(decor, l);WindowManager接口的實(shí)現(xiàn)是WindowManagerImpl,即實(shí)際調(diào)用的是WindowManagerImpl中的addView方法
代碼路徑:framework/core/java/android/view/WindowManagerImpl.java
@Override
public void addView(@NonNull View view, @NonNull ViewGroup.LayoutParams params) {
applyTokens(params);
//轉(zhuǎn)交給windowManagerGlobal,添加view
mGlobal.addView(view, params, mContext.getDisplayNoVerify(), mParentWindow,
mContext.getUserId());
}
WindowManagerImpl對窗口的管理交給WindowManagerGlobal,調(diào)用WindowManagerGlobal的addView方法
WindowManagerGlobal中對窗口的處理主要如下幾個(gè)步驟:
1.對WindowManagerImpl傳進(jìn)來的參數(shù)進(jìn)行檢查。
2.設(shè)置WindowManager.LayoutParams中的token、title等相關(guān)屬性。查看“【1.2 Token的創(chuàng)建與傳遞】”。
3.創(chuàng)建ViewRootImpl對象,并獲取客戶端與WMS通信的Session。查看“【1.3 ViewRootImpl的創(chuàng)建】”。
4.在WindowManagerGlobal中備份DecorView,WindowManager.LayoutParams以及ViewRootImpl。
5.調(diào)用ViewRootImpl,與WMS通信添加窗口。查看“【1.4 ViewRootImpl與WMS的通信】”。
代碼路徑:framework/core/java/android/view/WindowManagerGlobal.java
public void addView(View view, ViewGroup.LayoutParams params,
Display display, Window parentWindow, int userId) {
/*1.對WindowManagerImpl傳進(jìn)來的參數(shù)進(jìn)行檢查*/
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;
//此處的ParentWindow即當(dāng)Activity的PhoneWindow
if (parentWindow != null) {
/*2.為wparams的token進(jìn)行賦值*/
parentWindow.adjustLayoutParamsForSubWindow(wparams);
} else {
......
}
ViewRootImpl root;
View panelParentView = null;
synchronized (mLock) {
......
IWindowSession windowlessSession = null;
......
if (windowlessSession == null) {
/*3.新建ViewRootImpl,在新建時(shí)會通過WindowManagerGlobal獲取session*/
root = new ViewRootImpl(view.getContext(), display);
} else {
root = new ViewRootImpl(view.getContext(), display,
windowlessSession);
}
view.setLayoutParams(wparams);
/*4.在WindowManagerGlobal中備份DecorView,WindowManager.LayoutParams以及ViewRootImpl。*/
//當(dāng)前view加入到view列表中
mViews.add(view);
//將新建的viewRootImpl加入到root列表中
mRoots.add(root);
//將當(dāng)前布局參數(shù)加入到布局參數(shù)列表中
mParams.add(wparams);
// do this last because it fires off messages to start doing things
try {
/*5.調(diào)用ViewRootImpl,設(shè)置view,panelParentView為null,與WMS通信添加窗口*/
root.setView(view, wparams, panelParentView, userId);
} catch (RuntimeException e) {
// BadTokenException or InvalidDisplayException, clean up.
if (index >= 0) {
removeViewLocked(index, true);
}
throw e;
}
}
}
1.2 Token的創(chuàng)建與傳遞
parentWindow.adjustLayoutParamsForSubWindow(wparams);調(diào)用Window的adjustLayoutParamsForSubWindow()方法
在adjustLayoutParamsForSubWindow中會分別對WindowManager.LayoutParams中的token以及title進(jìn)行賦值。
1.首先針對子窗口、系統(tǒng)窗口以及應(yīng)用窗口做了不同的處理,此處我們只關(guān)注應(yīng)用窗口的處理。
2.其次將當(dāng)前PhoneWindow.mAppToken賦值給WindowManager.LayoutParams.token。
代碼路徑:framework/core/java/android/view/Window.java
void adjustLayoutParamsForSubWindow(WindowManager.LayoutParams wp) {
CharSequence curTitle = wp.getTitle();
if (wp.type >= WindowManager.LayoutParams.FIRST_SUB_WINDOW &&
wp.type <= WindowManager.LayoutParams.LAST_SUB_WINDOW) {
//對子窗口的Token以及Title賦值
......
} else if (wp.type >= WindowManager.LayoutParams.FIRST_SYSTEM_WINDOW &&
wp.type <= WindowManager.LayoutParams.LAST_SYSTEM_WINDOW) {
//對子窗口的Token以及Title賦值
......
} else {
//對應(yīng)用窗口的Token以及Title賦值
if (wp.token == null) {
//將當(dāng)前PhoneWindow的mAppToken賦值給wp.Token
wp.token = mContainer == null ? mAppToken : mContainer.mAppToken;
}
//將Title設(shè)置為mAppName
if ((curTitle == null || curTitle.length() == 0)
&& mAppName != null) {
wp.setTitle(mAppName);
}
}
//設(shè)置為packageName
if (wp.packageName == null) {
wp.packageName = mContext.getPackageName();
}
......
}
此處的mAppToken便是在Activity啟動時(shí),在ATMS端創(chuàng)建的Token。
接下來我們看看Token是如何從ATMS端傳遞過來,并賦值給PhoneWindow.mAppToken的

1.在ATMS端新建ActivityRecord時(shí),便新建了Token。并賦值給ActivityRecord.token
ActivityRecord繼承WindowToken
代碼路徑:framework/services/core/java/com/android/server/wm/ActivityRecord.java
private ActivityRecord(ActivityTaskManagerService _service, WindowProcessController _caller,
int _launchedFromPid, int _launchedFromUid, String _launchedFromPackage,
@Nullable String _launchedFromFeature, Intent _intent, String _resolvedType,
ActivityInfo aInfo, Configuration _configuration, ActivityRecord _resultTo,
String _resultWho, int _reqCode, boolean _componentSpecified,
boolean _rootVoiceInteraction, ActivityTaskSupervisor supervisor,
ActivityOptions options, ActivityRecord sourceRecord, PersistableBundle persistentState,
TaskDescription _taskDescription, long _createTime) {
//新建Token
super(_service.mWindowManager, new Token(), TYPE_APPLICATION, true,
null /* displayContent */, false /* ownerCanManageAppTokens */);
......
}
2.將ActivityRecord.token封裝在clientTransaction中,并將這個(gè)傳遞到客戶端
代碼路徑:framework/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java
boolean realStartActivityLocked(ActivityRecord r, WindowProcessController proc,
boolean andResume, boolean checkConfig) throws RemoteException {
......
final Task task = r.getTask();
final Task rootTask = task.getRootTask();
......
try {
......
try {
......
// Create activity launch transaction.
/*將ActivityRecord.token封裝在clientTransaction中*/
final ClientTransaction clientTransaction = ClientTransaction.obtain(
proc.getThread(), r.token);
final boolean isTransitionForward = r.isTransitionForward();
final IBinder fragmentToken = r.getTaskFragment().getFragmentToken();
clientTransaction.addCallback(LaunchActivityItem.obtain(new Intent(r.intent),
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.getFilteredReferrer(r.launchedFromPackage), task.voiceInteractor,
proc.getReportedProcState(), r.getSavedState(), r.getPersistentSavedState(),
results, newIntents, r.takeOptions(), isTransitionForward,
proc.createProfilerInfoIfNeeded(), r.assistToken, activityClientController,
r.shareableActivityToken, r.getLaunchedFromBubble(), fragmentToken));
......
// Schedule transaction.
/*將clientTransaction傳遞給客戶端*/
mService.getLifecycleManager().scheduleTransaction(clientTransaction);
......
} catch (RemoteException e) {
......
}
} finally {
......
}
......
return true;
}
final ClientTransaction clientTransaction = ClientTransaction.obtain( proc.getThread(), r.token);
在ClientTransaction中調(diào)用obtain方法,把ActivityRecord.token存到mActivityToken
代碼路徑:framework/core/java/android/app/servertransaction/ClientTransaction.java
/** Obtain an instance initialized with provided params. */
public static ClientTransaction obtain(IApplicationThread client, IBinder activityToken) {
ClientTransaction instance = ObjectPool.obtain(ClientTransaction.class);
if (instance == null) {
//創(chuàng)建ClientTransaction
instance = new ClientTransaction();
}
instance.mClient = client;
/*把ActivityRecord.token存到mActivityToken*/
//private IBinder mActivityToken;
instance.mActivityToken = activityToken;
return instance;
}
3.客戶端從ClientTransaction中獲取ATMS端傳來的Token,并傳遞到LaunchActivityItem中
代碼路徑:framework/core/java/android/app/servertransaction/TransactionExecutor.java
/** Cycle through all states requested by callbacks and execute them at proper times. */
@VisibleForTesting
public void executeCallbacks(ClientTransaction transaction) {
final List<ClientTransactionItem> callbacks = transaction.getCallbacks();
......
/*從ClientTransaction中獲取ATMS端傳來的Token*/
final IBinder token = transaction.getActivityToken();
ActivityClientRecord r = mTransactionHandler.getActivityClient(token);
......
final int size = callbacks.size();
for (int i = 0; i < size; ++i) {
final ClientTransactionItem item = callbacks.get(i);
......
/*將Token傳遞到LaunchActivityItem中*/
item.execute(mTransactionHandler, token, mPendingActions);
item.postExecute(mTransactionHandler, token, mPendingActions);
......
}
}
4.在LaunchActivityItem中將客戶端傳過來的Token保存在ActivityClientRecord.token中
代碼路徑:framework/core/java/android/app/servertransaction/LaunchActivityItem.java
@Override
public void execute(ClientTransactionHandler client, IBinder token,
PendingTransactionActions pendingActions) {
Trace.traceBegin(TRACE_TAG_ACTIVITY_MANAGER, "activityStart");
//將客戶端傳過來的Token保存在ActivityClientRecord的token中
ActivityClientRecord r = new ActivityClientRecord(token, mIntent, mIdent, mInfo,
mOverrideConfig, mCompatInfo, mReferrer, mVoiceInteractor, mState, mPersistentState,
mPendingResults, mPendingNewIntents, mActivityOptions, mIsForward, mProfilerInfo,
client, mAssistToken, mShareableActivityToken, mLaunchedFromBubble,
mTaskFragmentToken);
client.handleLaunchActivity(r, pendingActions, null /* customIntent */);
Trace.traceEnd(TRACE_TAG_ACTIVITY_MANAGER);
}
client.handleLaunchActivity(r, pendingActions, null /* customIntent */);ClientTransactionHandler調(diào)用handleLaunchActivity方法,ClientTransactionHandler為抽象類,其子類為ActivityThread,即實(shí)際調(diào)用的是該類中的handleLaunchActivity(),有從該方法中調(diào)用到了performLaunchActivity()
5.客戶端ActivityThread將ActivityClientRecord以及其對應(yīng)的token保存在ActivityThread.mActivities數(shù)組中,并調(diào)用Activity.attach將Token傳給Activity。
代碼路徑:framework/core/java/android/app/ActivityThread.java
/** Core implementation of activity launch. */
private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
......
try {
Application app = r.packageInfo.makeApplicationInner(false, mInstrumentation);
......
synchronized (mResourcesManager) {
/*將ActivityClientRecord以及其對應(yīng)的Token保存在mActivities中*/
//mActivities的類型為ArrayMap<IBinder, ActivityClientRecord>
mActivities.put(r.token, r);
}
if (activity != null) {
......
/*將Token賦值給Activity.mToken*/
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.activityConfigCallback,
r.assistToken, r.shareableActivityToken);
......
} catch (SuperNotCalledException e) {
throw e;
} catch (Exception e) {
......
}
return activity;
}
6.在Activity中將客戶端傳來的Token賦值給Activity.mToken。此外在該方法中還新建了PhoneWindow,并將PhoneWindow.mAppToken也設(shè)置為客戶端傳過來的Token。
代碼路徑:framework/core/java/android/app/Activity.java
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
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, IBinder assistToken,
IBinder shareableActivityToken) {
attachBaseContext(context);
mFragments.attachHost(null /*parent*/);
/*新建PhoneWindow*/
mWindow = new PhoneWindow(this, window, activityConfigCallback);
......
/*將客戶端傳過來的Token賦值給mToken*/
mToken = token;
......
/*PhoneWindow.mAppToken設(shè)置為當(dāng)前客戶端傳遞過來的Token*/
mWindow.setWindowManager(
(WindowManager)context.getSystemService(Context.WINDOW_SERVICE),
mToken, mComponent.flattenToString(),
(info.flags & ActivityInfo.FLAG_HARDWARE_ACCELERATED) != 0);
......
}
PhoneWindow繼承Window,setWindowManager實(shí)際調(diào)用的是其父類方法,把mAppToken設(shè)置為當(dāng)前客戶端傳遞過來的mToken
代碼路徑:framework/core/java/android/view/Window.java
/**
* Set the window manager for use by this Window to, for example,
* display panels. This is <em>not</em> used for displaying the
* Window itself -- that must be done by the client.
*
* @param wm The window manager for adding new windows.
*/
public void setWindowManager(WindowManager wm, IBinder appToken, String appName) {
//傳遞客戶端的mToken給appToken
setWindowManager(wm, appToken, appName, false);
}
/**
* Set the window manager for use by this Window to, for example,
* display panels. This is <em>not</em> used for displaying the
* Window itself -- that must be done by the client.
*
* @param wm The window manager for adding new windows.
*/
public void setWindowManager(WindowManager wm, IBinder appToken, String appName,
boolean hardwareAccelerated) {
/*把a(bǔ)ppToken賦值給mAppToken*/
mAppToken = appToken;
mAppName = appName;
mHardwareAccelerated = hardwareAccelerated;
if (wm == null) {
wm = (WindowManager)mContext.getSystemService(Context.WINDOW_SERVICE);
}
mWindowManager = ((WindowManagerImpl)wm).createLocalWindowManager(this);
}
1.3 ViewRootImpl的創(chuàng)建
root = new ViewRootImpl(view.getContext(), display);之前在【1.1 Activity走到onresume后】的流程中有調(diào)用創(chuàng)建ViewRootImpl,這里我們看下ViewRootImpl的構(gòu)造方法
代碼路徑:framework/core/java/android/view/ViewRootImpl.java
public ViewRootImpl(Context context, Display display) {
this(context, display, WindowManagerGlobal.getWindowSession(),
false /* useSfChoreographer */);
}
public ViewRootImpl(@UiContext Context context, Display display, IWindowSession session) {
this(context, display, session, false /* useSfChoreographer */);
}
public ViewRootImpl(@UiContext Context context, Display display, IWindowSession session,
boolean useSfChoreographer) {
mContext = context;
mWindowSession = session;
......
}
從這個(gè)構(gòu)造方法中我們可以看出,通過WindowManagerGlobal.getWindowSession獲取到客戶端與WMS溝通的橋梁IWindowSession,并將其賦值給ViewRootImpl.mWindowSession。
下面我們查看WindowManagerGlobal中是如何獲取Session的。
1.通過getWindowManagerService獲取IWindowManager,而WindowManagerService則實(shí)現(xiàn)了這個(gè)Binder接口。
2.調(diào)用IWindowManager.openSession方法即WMS.openSession,在WMS端便會新建Session。至此客戶端與WMS通信的橋梁便已經(jīng)搭建好了
代碼路徑:framework/core/java/android/view/WindowManagerGlobal.java
@UnsupportedAppUsage
public static IWindowSession getWindowSession() {
synchronized (WindowManagerGlobal.class) {
if (sWindowSession == null) {
try {
// Emulate the legacy behavior. The global instance of InputMethodManager
// was instantiated here.
// TODO(b/116157766): Remove this hack after cleaning up @UnsupportedAppUsage
InputMethodManager.ensureDefaultInstanceForDefaultDisplayIfNecessary();
/*1.獲取Binder*/
IWindowManager windowManager = getWindowManagerService();
/*2.調(diào)用WMS的openSession*/
sWindowSession = windowManager.openSession(
new IWindowSessionCallback.Stub() {
@Override
public void onAnimatorScaleChanged(float scale) {
ValueAnimator.setDurationScale(scale);
}
});
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
return sWindowSession;
}
}
從代碼中可以看出如果sWindowSession不為空則直接返回,sWindowSession為當(dāng)前WindowManagerGlobal屬性,且WindowManagerGloba又是單例的,所以客戶端一個(gè)進(jìn)程中只有一個(gè)IWindowSession與WMS通信。如果sWindowSession為空,則會創(chuàng)建IWindowSession。
調(diào)用WindowManagerService中的openSession,新建Session
代碼路徑:framework/services/core/java/com/android/server/wm/WindowManagerService.java
@Override
public IWindowSession openSession(IWindowSessionCallback callback) {
/*新建Session*/
return new Session(this, callback);
}
1.4 ViewRootImpl與WMS的通信
root.setView(view, wparams, panelParentView, userId);之前在【1.1 Activity走到onresume后】的流程中有調(diào)用ViewRootImpl與WMS的通信,繼續(xù)看看
當(dāng)前方法是與WMS進(jìn)行通信添加窗口的入口,在此處我們只關(guān)注兩點(diǎn):
1.requestLayout()該方法會調(diào)用到doTraversal(),之后調(diào)用performTraversals(),最終調(diào)用到relayoutWindow()和reportDrawFinished()流程,在通過Session與服務(wù)端通信
2.mWindowSession.addToDisplayAsUser,與服務(wù)端進(jìn)行Binder通信,調(diào)用Session的addToDisplayAsUser方法。
/**
* We have one child
*/
public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView) {
setView(view, attrs, panelParentView, UserHandle.myUserId());
}
/**
* We have one child
*/
public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView,
int userId) {
synchronized (this) {
if (mView == null) {
mView = view;
......
//將布局參數(shù)拷貝紙mWindowAttributes
mWindowAttributes.copyFrom(attrs);
//設(shè)置包名
if (mWindowAttributes.packageName == null) {
mWindowAttributes.packageName = mBasePackageName;
}
mWindowAttributes.privateFlags |=
WindowManager.LayoutParams.PRIVATE_FLAG_USE_BLAST;
attrs = mWindowAttributes;
......
// Keep track of the actual window flags supplied by the client.
//獲取當(dāng)前布局的flags
mClientWindowLayoutFlags = attrs.flags;
......
int res; /* = WindowManagerImpl.ADD_OKAY; */
// Schedule the first layout -before- adding to the window
// manager, to make sure we do the relayout before receiving
// any other events from the system.
/*請求布局,對應(yīng)服務(wù)端layoutWindow流程*/
requestLayout();
InputChannel inputChannel = null;
if ((mWindowAttributes.inputFeatures
& WindowManager.LayoutParams.INPUT_FEATURE_NO_INPUT_CHANNEL) == 0) {
inputChannel = new InputChannel();
}
......
try {
......
/*與服務(wù)端進(jìn)行Binder通信,調(diào)用Session的addToDisplayAsUser方法*/
//執(zhí)行addWindow的相關(guān)流程
res = mWindowSession.addToDisplayAsUser(mWindow, mWindowAttributes,
getHostVisibility(), mDisplay.getDisplayId(), userId,
mInsetsController.getRequestedVisibilities(), inputChannel, mTempInsets,
mTempControls);
......
} catch (RemoteException e) {
......
} finally {
if (restore) {
attrs.restore();
}
}
......
if (DEBUG_LAYOUT) Log.v(mTag, "Added window " + mWindow);
if (res < WindowManagerGlobal.ADD_OKAY) {
mAttachInfo.mRootView = null;
mAdded = false;
mFallbackEventHandler.setView(null);
unscheduleTraversals();
setAccessibilityFocus(null, null);
switch (res) {
case WindowManagerGlobal.ADD_BAD_APP_TOKEN:
case WindowManagerGlobal.ADD_BAD_SUBWINDOW_TOKEN:
throw new WindowManager.BadTokenException(
"Unable to add window -- token " + attrs.token
+ " is not valid; is your activity running?");
case WindowManagerGlobal.ADD_NOT_APP_TOKEN:
throw new WindowManager.BadTokenException(
"Unable to add window -- token " + attrs.token
+ " is not for an application");
case WindowManagerGlobal.ADD_APP_EXITING:
throw new WindowManager.BadTokenException(
"Unable to add window -- app for token " + attrs.token
+ " is exiting");
case WindowManagerGlobal.ADD_DUPLICATE_ADD:
throw new WindowManager.BadTokenException(
"Unable to add window -- window " + mWindow
+ " has already been added");
case WindowManagerGlobal.ADD_STARTING_NOT_NEEDED:
// Silently ignore -- we would have just removed it
// right away, anyway.
return;
case WindowManagerGlobal.ADD_MULTIPLE_SINGLETON:
throw new WindowManager.BadTokenException("Unable to add window "
+ mWindow + " -- another window of type "
+ mWindowAttributes.type + " already exists");
case WindowManagerGlobal.ADD_PERMISSION_DENIED:
throw new WindowManager.BadTokenException("Unable to add window "
+ mWindow + " -- permission denied for window type "
+ mWindowAttributes.type);
case WindowManagerGlobal.ADD_INVALID_DISPLAY:
throw new WindowManager.InvalidDisplayException("Unable to add window "
+ mWindow + " -- the specified display can not be found");
case WindowManagerGlobal.ADD_INVALID_TYPE:
throw new WindowManager.InvalidDisplayException("Unable to add window "
+ mWindow + " -- the specified window type "
+ mWindowAttributes.type + " is not valid");
case WindowManagerGlobal.ADD_INVALID_USER:
throw new WindowManager.BadTokenException("Unable to add Window "
+ mWindow + " -- requested userId is not valid");
}
throw new RuntimeException(
"Unable to add window -- unknown error code " + res);
}
......
}
}
}
其中關(guān)鍵的添加代碼為
res = mWindowSession.addToDisplayAsUser(mWindow, mWindowAttributes,
getHostVisibility(), mDisplay.getDisplayId(), userId,
mInsetsController.getRequestedVisibilities(), inputChannel, mTempInsets,
mTempControls);
addToDisplayAsUser()方法最終會走到WindowManagerService.java的addWindow方法,addWindow方法的返回值最后會返回給res,之后回看ViewRootImpl的setView方法,返回值如果滿足if (res < WindowManagerGlobal.ADD_OKAY)條件,那么會根據(jù)switch (res)中對應(yīng)的case拋出異常。
至此,客戶端流程結(jié)束,后面進(jìn)入服務(wù)端流程。
————————————————
版權(quán)聲明:本文為CSDN博主「yi諾千金」的原創(chuàng)文章,遵循CC 4.0 BY-SA版權(quán)協(xié)議,轉(zhuǎn)載請附上原文出處鏈接及本聲明。
原文鏈接:https://blog.csdn.net/yimelancholy/article/details/130339779