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的服务端,那么它自然的接收客户端的请求,那它主要提供什么样的服务呢? 看下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();

原文地址:https://www.cnblogs.com/mingfeng002/p/10951883.html

时间: 2024-11-13 14:07:42

Android在WindowManagerService和ActivityManagerService中的Token的相关文章

Android客户端与服务器交互中的token

学习Token Token是什么? Token是服务端生成的一串字符串,以作客户端进行请求的一个令牌,当第一次登录后,服务器生成一个Token便将此Token返回给客户端,以后客户端只需带上这个Token前来请求数据即可,无需再次带上用户名和密码. Token的引入-- Token是在客户端频繁向服务端请求数据,服务端频繁的去数据库查询用户名和密码并进行对比,判断用户名和密码正确与否,并作出相应提示,在这样的背景下,Token便应运而生 使用Token的目的-- Token的目的是为了减轻服务器

Android系统在新进程中启动自定义服务过程(startService)的原理分析

在编写Android应用程序时,我们一般将一些计算型的逻辑放在一个独立的进程来处理,这样主进程仍然可以流畅地响应界面事件,提高用户体验.Android系统为我们提供了一个Service类,我们可以实现一个以Service为基类的服务子类,在里面实现自己的计算型逻辑,然后在主进程通过startService函数来启动这个服务.在本文中,将详细分析主进程是如何通过startService函数来在新进程中启动自定义服务的. 在主进程调用startService函数时,会通过Binder进程间通信机制来

【转】Android 之ActivityThead、ActivityManagerService 与activity的管理和创建

在android中,Activity是四大组件中比较重要的一个(当然其他的也比较重要),那么android中是怎样管理这些activity的?应用的进程和主线程是怎么创建的,应用的消息循环又是在什么时候创建的?在这篇文章中将详细介绍: 先来看下涉及到的类,通过以下类图对整体先有个大概的印象: ActivityThread: ActivityThread主要用来启动应用程序的主线程,并且管理在应用端跟用户打交道的activity.在应用端的activity信息全部被存储在ActivityThrea

Android如何在java代码中设置margin

习惯了直接在xml里设置margin(距离上下左右都是10dip),如: <ImageView android:layout_margin="10dip" android:src="@drawable/image" /> 只是有些情况下,需要在java代码里来写. API中,android.view.ViewGroup.MarginLayoutParams有个方法setMargins(left, top, right, bottom).可是View本身没

Android 使用ContentProvider扫描手机中的图片,仿微信显示本地图片效果

首先我们先看第一个界面吧,使用将手机中的图片扫描出来,然后根据图片的所在的文件夹将其分类出来,并显示所在文件夹里面的一张图片和文件夹中图片个数,我们根据界面元素(文件夹名, 文件夹图片个数,文件夹中的一张图片)使用一个实体对象ImageBean来封装这三个属性 package com.example.imagescan; /** * GridView的每个item的数据对象 * * @author len * */ public class ImageBean{ /** * 文件夹的第一张图片路

【Android布局】在程序中设置android:gravity 和 android:layout_Gravity属性

在进行UI布局的时候,可能常常会用到 android:gravity  和 android:layout_Gravity 这两个属性. 关于这两个属性的差别,网上已经有许多人进行了说明,这边再简单说一下. (资料来自网络) LinearLayout有两个很类似的属性: android:gravity与android:layout_gravity. 他们的差别在于: android:gravity 属性是对该view中内容的限定.比方一个button 上面的text. 你能够设置该text 相对于

在低于android 5.0的版本中ActionBar不显示

我从ABS切换到AppCompat与Material theme(仅适用于API21) 我的配置文件如下: <application android:theme="@style/AppStyle" <-- values folder --> <style name="AppStyle" parent="@style/AudioRecTheme"> <style name="AudioRecTheme&

在Android的c/c++代码中使用LOG

在Android中,Java代码通过android.util.Log输出Log信息,同样的本地c/c++代码也提供了相对应而且是更多的接口.Android直接在头文件(system/core/include/cutils/log.h)里定义了一些日志输出的宏,这些宏比android.util.Log提供了更多的日志输出接口.因此,使用这些宏,就可以进行和java代码中一样的日志输出.宏LOGD(),LOGE(),LOGI(),LOGV(),LOGW(),LOGD()分别对应android.uti

android 2.3.4 编译中出错和解决办法

需要安装的一些库,有如下一些: sudo apt-get install git-core gnupg flex bison gperf build-essential \ zip curl zlib1g-dev libc6-dev lib32ncurses5-dev ia32-libs \ x11proto-core-dev libx11-dev lib32readline5-dev lib32z-dev \ libgl1-mesa-dev g++-multilib mingw32 tofro