Android在WindowManagerService和ActivityManagerService中的Token


 

 https://upload-images.jianshu.io/upload_images/5688445-6cf0575bb52ccb45.png

1. ActivityRecord中的token

ActivityRecord在ActivityStackSupervisor的startActivityLocked初始化

http://androidxref.com/6.0.1_r10/xref/frameworks/base/services/core/java/com/android/server/am/ActivityStackSupervisor.java

http://androidxref.com/6.0.1_r10/xref/frameworks/base/services/core/java/com/android/server/am/ActivityRecord.java

final int startActivityLocked(IApplicationThread caller,
            Intent intent, String resolvedType, ActivityInfo aInfo,
            IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor,
            IBinder resultTo, String resultWho, int requestCode,
            int callingPid, int callingUid, String callingPackage,
            int realCallingPid, int realCallingUid, int startFlags, Bundle options,
            boolean componentSpecified, ActivityRecord[] outActivity, ActivityContainer container,
            TaskRecord inTask) {
 
        ActivityRecord r = new ActivityRecord(mService, callerApp, callingUid, callingPackage,
                intent, resolvedType, aInfo, mService.mConfiguration, resultRecord, resultWho,
                requestCode, componentSpecified, this, container, options);
 
 
        err = startActivityUncheckedLocked(r, sourceRecord, voiceSession, voiceInteractor,
                startFlags, true, options, inTask);
}
ActivityRecord
    ActivityRecord(ActivityManagerService _service, ProcessRecord _caller,
            int _launchedFromUid, String _launchedFromPackage, Intent _intent, String _resolvedType,
            ActivityInfo aInfo, Configuration _configuration,
            ActivityRecord _resultTo, String _resultWho, int _reqCode,
            boolean _componentSpecified, boolean _rootVoiceInteraction,
            ActivityStackSupervisor supervisor,
            ActivityContainer container, Bundle options) {
        service = _service;
        appToken = new Token(this, service);
        info = aInfo;
        launchedFromUid = _launchedFromUid;
        launchedFromPackage = _launchedFromPackage;
        userId = UserHandle.getUserId(aInfo.applicationInfo.uid);
        intent = _intent;
        shortComponentName = _intent.getComponent().flattenToShortString();
        resolvedType = _resolvedType;
        componentSpecified = _componentSpecified;
        rootVoiceInteraction = _rootVoiceInteraction;
        configuration = _configuration;
        stackConfigOverride = (container != null)
                ? container.mStack.mOverrideConfig : Configuration.EMPTY;
        resultTo = _resultTo;
        resultWho = _resultWho;
        requestCode = _reqCode;
        state = ActivityState.INITIALIZING;
    //...

}
Token是ActivityRecord內部類330行
http://androidxref.com/6.0.1_r10/xref/frameworks/base/services/core/java/com/android/server/am/ActivityRecord.java
   static class Token extends IApplicationToken.Stub {
        private final WeakReference<ActivityRecord> weakActivity;
        private final ActivityManagerService mService;

        Token(ActivityRecord activity, ActivityManagerService service) {
            weakActivity = new WeakReference<>(activity);
            mService = service;
        }
    //...
}    

啟動一個Activity的時候會為這個Activity生成一個ActivityRecord對象,該對象用於AMS管理跟蹤,而 Token就在這里誕生了。

Token類實現了IApplicationToken.Stub,也就是作為Binder的服務端,那么它自然的接收客戶端的請求,那它主要提供什么樣的服務呢?

看下android/view/IApplicationToken.aidl

interface IApplicationToken
{
    void windowsDrawn();
    void windowsVisible();
    void windowsGone();
    boolean keyDispatchingTimedOut(String reason);
    long getKeyDispatchingTimeout();
}

可以看出,大部分是WindowManagerService用於通知ActivityManagerService的關於Window的消息,也有key的相關消息

2. WMS中的token

 WMS專為Activity實現了一個WindowToken的子類:AppWindowToken

http://androidxref.com/6.0.1_r10/xref/frameworks/base/services/core/java/com/android/server/wm/AppWindowToken.java

具體位置為ActivityStack.startActivityLocked(),也就是啟動Activity的時候。相關代碼如下:ActivityStack.startActivityLocked()

http://androidxref.com/6.0.1_r10/xref/frameworks/base/services/core/java/com/android/server/am/ActivityStack.java

private final void startActivityLocked(......) {
    ......
    mService.mWindowManager.addAppToken(addPos,r.appToken, r.task.taskId,
                               r.info.screenOrientation, r.fullscreen);
    ......
}

startActivityLocked()向WMS聲明r.appToken作為此Activity的Token,這個Token是在ActivityRecord的構造函數中創建的。

將ActivityRecord中的appToken加入到WMS中

http://androidxref.com/6.0.1_r10/xref/frameworks/base/services/core/java/com/android/server/wm/WindowManagerService.java

public void addAppToken( ) {
            //生成ActivityRecord在WMS中對應的AppWindowToken,並引用到ActivityRecord中的Token,見p2
            atoken = new AppWindowToken(this, token, voiceInteraction); 
            //如果沒有Task, 就創建一個task, 並加入到stack中,
            //這里的task/stack都是與AMS中task/stack就一一對應的。 見p3
            Task task = mTaskIdToTask.get(taskId); 

            if (task == null) {
                task = createTaskLocked(taskId, stackId, userId, atoken, taskBounds, config);
            }
            //將AppWindowToken加入到task中管理起來
            task.addAppToken(addPos, atoken, taskResizeMode, homeTask); 
            mTokenMap.put(token.asBinder(), atoken); //加入到mTokenMap中, 見p4
}

 http://androidxref.com/6.0.1_r10/xref/frameworks/base/services/core/java/com/android/server/wm/AppWindowToken.java

AppWindowToken(WindowManagerService _service, IApplicationToken _token,
            boolean _voiceInteraction) {
        //將token的binder對象給AppWindowToken的父類WindowToken引用
        super(_service, _token.asBinder(), 
                WindowManager.LayoutParams.TYPE_APPLICATION, true);
        appWindowToken = this;
        appToken = _token;  //引用到ActivityRecord中的Token
        voiceInteraction = _voiceInteraction;
        mInputApplicationHandle = new InputApplicationHandle(this);
        mAppAnimator = new AppWindowAnimator(this);
    }

 

wtoken.appToken.windowsDrawn();
wtoken.appToken.windowsVisible(); 
appWindowToken.appToken.keyDispatchingTimedOut(reason);

作用

WindowManagerService中AppWindowToken保存着ActivityManagerService Binder對象,用來向AMS傳遞Window和按鍵的一些信息.
另外的一個用處是作為 mTokenMap的key

mTokenMap.put(token.asBinder(), atoken);

3. App中的token

attachApplicationLocked
    realStartActivityLocked
        app.thread.scheduleLaunchActivity(new Intent(r.intent), r.appToken, );
public final void scheduleLaunchActivity(Intent intent, IBinder token, ) {
            //生成App中的ActivityClientRecord
            ActivityClientRecord r = new ActivityClientRecord();
            r.token = token;  //將AMS中的token保存到 ActivityClientRecord中 見P5
}

將AMS中的token保存到 ActivityClientRecord中

http://androidxref.com/6.0.1_r10/xref/frameworks/base/core/java/android/app/ActivityThread.java

public final class ActivityThread {
   //...
    private ContextImpl mSystemContext;

    static IPackageManager sPackageManager;

    final ApplicationThread mAppThread = new ApplicationThread();
    final Looper mLooper = Looper.myLooper();
    final H mH = new H();
    final ArrayMap<IBinder, ActivityClientRecord> mActivities = new ArrayMap<>(); // List of new activities (via ActivityRecord.nextIdle) that should
    // be reported when next we idle.
    ActivityClientRecord mNewActivities = null;
    // Number of activities that are currently visible on-screen.
    int mNumVisibleActivities = 0;
    WeakReference<AssistStructure> mLastAssistStructure;
    final ArrayMap<IBinder, Service> mServices = new ArrayMap<>();
  //...
}

AMS將ActivityRecord的appToken傳遞給App進程。

 
         
//ActivityThread
private void handleLaunchActivity(ActivityClientRecord r, Intent customIntent) {
    //...
    //獲取WindowManagerService的Binder引用(proxy端)。
    WindowManagerGlobal.initialize();

    //會調用Activity的onCreate,onStart,onResotreInstanceState方法
    Activity a = performLaunchActivity(r, customIntent);
    if (a != null) {
        //...
        //會調用Activity的onResume方法.
        handleResumeActivity(r.token, false, r.isForward,
                !r.activity.mFinished && !r.startsNotResumed, r.lastProcessedSeq, reason);

        //...
    } 

}
//ActivityThread

   private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {

        //通過類加載器創建Activity
        Activity activity = mInstrumentation.newActivity(cl, component.getClassName(), r.intent);

        //...        

        //通過LoadedApk的makeApplication方法來創建Application對象
        Application app = r.packageInfo.makeApplication(false, mInstrumentation);


        if (activity != null) {
            //...
            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);
            //...

            //onCreate
            mInstrumentation.callActivityOnCreate(activity, r.state);

            //onStart
            activity.performStart();

        }
        return activity;
    }

在Activity的attach()方法里,系統會創建Activity所屬的Window對象並為其設置回調接口,由於Activity實現了Window的Callback接口,因此當Window接收到外界的狀態改變時就會回調Activity的方法。Callback接口中的方法很多,下面舉幾個比較眼熟的方法。

public interface Callback {

        public boolean dispatchTouchEvent(MotionEvent event);

        public View onCreatePanelView(int featureId);

        public boolean onMenuItemSelected(int featureId, MenuItem item);

        public void onContentChanged();

        public void onWindowFocusChanged(boolean hasFocus);

        public void onAttachedToWindow();

        public void onDetachedFromWindow();
    }
//Activity

final void attach(...) {
        //綁定上下文
        attachBaseContext(context);

        //創建Window,PhoneWindow是Window的唯一具體實現類
        mWindow = new PhoneWindow(this, window);//此處的window==null,但不影響
        mWindow.setWindowControllerCallback(this);
        mWindow.setCallback(this);
        //...
        //設置WindowManager
        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());
        }
        //創建完后通過getWindowManager就可以得到WindowManager實例
        mWindowManager = mWindow.getWindowManager();//其實它是WindowManagerImpl
    }

    @Override
    public Object getSystemService(@ServiceName @NonNull String name) {
        //...
        if (WINDOW_SERVICE.equals(name)) {
            return mWindowManager;
        } 
        return super.getSystemService(name);
    }

等,等一下。看到這里是不是有點懵,Activity的getSystemService根本沒有創建WindowManager,那么mWindow.setWindowManager()設置的豈不是空的WindowManager,那這樣它的下一步mWindowManager = mWindow.getWindowManager()豈不是無線空循環?

因為PhoneWindow中並沒有setWindowManager()方法,所以我們打開Window類看看。

//Window


    public 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 
        mWindowManager = ((WindowManagerImpl)wm).createLocalWindowManager(this);
    }



//在WindowManagerImpl類中
    public WindowManagerImpl createLocalWindowManager(Window parentWindow) {
        return new WindowManagerImpl(mContext, parentWindow);
    }
類似於PhoneWindow和Window的關系,WindowManager是一個接口,具體的實現是WindowManagerImpl。

作用
Activity中的token涉及到多個地方,

  • ActivityClientRecord
    這個類是Activity在ActivityThread中一一對應的,一個APP有多個Activity, 也就是說有多個ActivityClientRecord, 那么當AMS要啟動一個Activity的時候,怎么樣找到APP中正確的那個Activity呢?答案就是通過Token,
    如:
public final ActivityClientRecord performResumeActivity(IBinder token,
            boolean clearHide, String reason) {
        ActivityClientRecord r = mActivities.get(token);
        r.activity.performResume();
}

先通過token找到ActivityClientRecord,然后再通過ActivityClientRecord中的activity就找到了正確的Activity了

  • Activity
    Activity中Token主要用於在請求AMS服務時用於定位到具體到AMS中正確的ActivityRecord
    比如進入PIP模式,通過Token,AMS就可以知道具體是哪個Activity進入PIP,
    public void enterPictureInPictureMode() {
        try {
            ActivityManagerNative.getDefault().enterPictureInPictureMode(mToken);
        } catch (RemoteException e) {
        }
    }

又比如 startActivityForResult,希望在finish時得到一些結果,那么AMS在finish那個Activity時,會把result傳遞給resultTo(mToken對應的那個Activity),

    public void startActivityForResult(@RequiresPermission Intent intent, int requestCode,
            @Nullable Bundle options) {
        if (mParent == null) {
            Instrumentation.ActivityResult ar =
                mInstrumentation.execStartActivity(
                    this, mMainThread.getApplicationThread(), mToken, this,
                    intent, requestCode, options);
  • Window
    Window中的Token主要是傳給LayoutParams, 見下面分析

4. WindowManager.LayoutParams里的token

WindowManager.LayoutParams是App中的,但是這里單獨拿出來,是因為WMS會使用到它中的Token

ddView->setView

public void addView(View view, ViewGroup.LayoutParams params,
            Display display, Window parentWindow) {
        if (parentWindow != null) {//這里parentWindow為PhoneWindow
            parentWindow.adjustLayoutParamsForSubWindow(wparams);
        } 
}

void adjustLayoutParamsForSubWindow(WindowManager.LayoutParams wp) {
       ...
       } else {
             //這里為null, 且mContainer也為空,所以將mAppToken直接賦值給wp.token
            if (wp.token == null) {
                wp.token = mContainer == null ? mAppToken : mContainer.mAppToken;
            }
      }
}

由上代碼可知WindowManager.LayoutParams的token為Window中的mAppToken也就是AMS中ActivityRecord中的Token 見p8


作用

WindowManager.LayoutParams中的 token傳遞給WMS,
另外它的大部分作用是一致性判斷

5. WindowState中的token

public int addWindow(WindowManager.LayoutParams attrs) {
            //attrs.token即是圖中的p8, 這里拿到的token不為null, 具體參考 **WMS中的token**
            WindowToken token = mTokenMap.get(attrs.token); 
            ...
            if (type >= FIRST_APPLICATION_WINDOW && type <= LAST_APPLICATION_WINDOW){
                //這里atoken即是WindowToken的子類 AppWindowToken, 具體見p2
                atoken = token.appWindowToken;  
           }
            WindowState win = new WindowState(this, session, client, token,
                    attachedWindow, appOp[0], seq, attrs, viewVisibility, displayContent);
}

WindowState(WindowManagerService service, Session s, IWindow c, WindowToken token,
           WindowState attachedWindow, int appOp, int seq, WindowManager.LayoutParams a) {
        mToken = token; //WindowState引用到WindowToken

        WindowState appWin = this;
        while (appWin.isChildWindow()) {
            //一個Activity上可能有多個窗口,這里找到父窗口
            appWin = appWin.mAttachedWindow;  
        }
        WindowToken appToken = appWin.mToken; // 
        while (appToken.appWindowToken == null) {
            WindowToken parent = mService.mTokenMap.get(appToken.token);
            if (parent == null || appToken == parent) {
                break;
            }
            appToken = parent;
        }
        mRootToken = appToken;
        //這里mAppToken就是WindowToken的子類 AppWindowToken. 見P4
        mAppToken = appToken.appWindowToken; 

從上面代碼看出WindowState也間接有ActivityRecord中的Token的引用。

作用

WMS中的token是通過WindowManager.LayoutParams傳過來的,作用之一是作為
mTokensMap中的key值用來儲存對應的WindowToken
作用之二是通知AMS一些消息,如

mActivityManager.notifyEnterAnimationComplete(atoken.token);
wtoken.appToken.windowsVisible();

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM