应用Token的流程和作用

来源:互联网 发布:知乎live 编辑:程序博客网 时间:2024/05/23 13:50

android系统中,Binder有两个重要的用途:

  1. 获取Binder地址,进行跨进程调用;
  2. 在多个进程中标识身份,确保调用安全。

android中Token就是以Binder的身份出现,主要进行身份的标识,验证。

这里写图片描述

步骤一

当桌面点击图标,启动一个普通的应用程序的时候。框架AMS解析传入的intent,生成了ActivityRecord对象。
ActivityRecord:

属性appToken

final IApplicationToken.Stub appToken; // window manager token

构造方法,创建了appToken

    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, ActivityOptions options, ActivityRecord sourceRecord) {        service = _service;        **appToken = new Token(this, service);**        info = aInfo;        launchedFromUid = _launchedFromUid;        launchedFromPackage = _launchedFromPackage;        userId = UserHandle.getUserId(aInfo.applicationInfo.uid);        intent = _intent;

在ActivityStart类中创建ActivityRecord,然后在ActivityRecord的构造函数中生成了appToken

 final int startActivityLocked(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,            ActivityOptions options, boolean ignoreTargetSecurity, boolean componentSpecified,            ActivityRecord[] outActivity, ActivityStackSupervisor.ActivityContainer container,            TaskRecord inTask) {        ActivityRecord r = new ActivityRecord(mService, callerApp, callingUid, callingPackage,                intent, resolvedType, aInfo, mService.mConfiguration, resultRecord, resultWho,                requestCode, componentSpecified, voiceSession != null, mSupervisor, container,                options, sourceRecord);  }

步骤二
AMS把ActivityRecord中的appToken通过各种流程传递给WMS。
ActivityStarter:

    private int startActivityUnchecked(final ActivityRecord r, ActivityRecord sourceRecord,            IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor,            int startFlags, boolean doResume, ActivityOptions options, TaskRecord inTask) {        //mTargetStack就是ActivityStack,即将要启动的activity的stack        mTargetStack.startActivityLocked(mStartActivity, newTask, mKeepCurTransition, mOptions);    }

ActivityStack:

    final void startActivityLocked(ActivityRecord r, boolean newTask, boolean keepCurTransition,            ActivityOptions options) {            addConfigOverride(r, task);     }    void addConfigOverride(ActivityRecord r, TaskRecord task) {        final Rect bounds = task.updateOverrideConfigurationFromLaunchBounds();        // 跳转到WMS        mWindowManager.addAppToken(task.mActivities.indexOf(r), r.appToken,                r.task.taskId, mStackId, r.info.screenOrientation, r.fullscreen,                (r.info.flags & FLAG_SHOW_FOR_ALL_USERS) != 0, r.userId, r.info.configChanges,                task.voiceSession != null, r.mLaunchTaskBehind, bounds, task.mOverrideConfig,                task.mResizeMode, r.isAlwaysFocusable(), task.isHomeTask(),                r.appInfo.targetSdkVersion, r.mRotationAnimationHint);        r.taskConfigOverride = task.mOverrideConfig;    }

WMS:

    public void addAppToken(int addPos, IApplicationToken token, int taskId, int stackId,            int requestedOrientation, boolean fullscreen, boolean showForAllUsers, int userId,            int configChanges, boolean voiceInteraction, boolean launchTaskBehind,            Rect taskBounds, Configuration config, int taskResizeMode, boolean alwaysFocusable,            boolean homeTask, int targetSdkVersion, int rotationAnimationHint) {        if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS,                "addAppToken()")) {            throw new SecurityException("Requires MANAGE_APP_TOKENS permission");        }        // Get the dispatching timeout here while we are not holding any locks so that it        // can be cached by the AppWindowToken.  The timeout value is used later by the        // input dispatcher in code that does hold locks.  If we did not cache the value        // here we would run the chance of introducing a deadlock between the window manager        // (which holds locks while updating the input dispatcher state) and the activity manager        // (which holds locks while querying the application token).        long inputDispatchingTimeoutNanos;        try {            inputDispatchingTimeoutNanos = token.getKeyDispatchingTimeout() * 1000000L;        } catch (RemoteException ex) {            Slog.w(TAG_WM, "Could not get dispatching timeout.", ex);            inputDispatchingTimeoutNanos = DEFAULT_INPUT_DISPATCHING_TIMEOUT_NANOS;        }        synchronized(mWindowMap) {            AppWindowToken atoken = findAppWindowToken(token.asBinder());            if (atoken != null) {                Slog.w(TAG_WM, "Attempted to add existing app token: " + token);                return;            }            //这里的token,应该是ActivityRecord中IApplicationToken.Stub的代理,            //然后根据这个代理,创建AppWindowToken            atoken = new AppWindowToken(this, token, voiceInteraction);            atoken.inputDispatchingTimeoutNanos = inputDispatchingTimeoutNanos;            atoken.appFullscreen = fullscreen;            atoken.showForAllUsers = showForAllUsers;            atoken.targetSdk = targetSdkVersion;            atoken.requestedOrientation = requestedOrientation;            atoken.layoutConfigChanges = (configChanges &                    (ActivityInfo.CONFIG_SCREEN_SIZE | ActivityInfo.CONFIG_ORIENTATION)) != 0;            atoken.mLaunchTaskBehind = launchTaskBehind;            atoken.mAlwaysFocusable = alwaysFocusable;            if (DEBUG_TOKEN_MOVEMENT || DEBUG_ADD_REMOVE) Slog.v(TAG_WM, "addAppToken: " + atoken                    + " to stack=" + stackId + " task=" + taskId + " at " + addPos);            atoken.mRotationAnimationHint = rotationAnimationHint;            Task task = mTaskIdToTask.get(taskId);            if (task == null) {                task = createTaskLocked(taskId, stackId, userId, atoken, taskBounds, config);            }            task.addAppToken(addPos, atoken, taskResizeMode, homeTask);            //**将atoken放入到mTokenMap中,等应用程序addWindow时,进行身份验证**            //其中token.asBinder()是IApplicationToken.Stub的代理,atoken就是根据代理,得到对应AppWindowToken            mTokenMap.put(token.asBinder(), atoken);            // Application tokens start out hidden.            atoken.hidden = true;            atoken.hiddenRequested = true;        }    }

步骤三
当框架通过ApplicationThread的代理回调到ActivityThread的时候,将对应的步骤一种生成的token代理传入。

ActivityStackSupervisor:

    void startSpecificActivityLocked(ActivityRecord r,            boolean andResume, boolean checkConfig) {        // Is this activity's application already running?        ProcessRecord app = mService.getProcessRecordLocked(r.processName,                r.info.applicationInfo.uid, true);        r.task.stack.setLaunchTime(r);        //进程存在的情况下,启动进程中的activity        if (app != null && app.thread != null) {            try {                if ((r.info.flags&ActivityInfo.FLAG_MULTIPROCESS) == 0                        || !"android".equals(r.info.packageName)) {                    // Don't add this if it is a platform component that is marked                    // to run in multiple processes, because this is actually                    // part of the framework so doesn't make sense to track as a                    // separate apk in the process.                    app.addPackage(r.info.packageName, r.info.applicationInfo.versionCode,                            mService.mProcessStats);                }                realStartActivityLocked(r, app, andResume, checkConfig);                return;            } catch (RemoteException e) {                Slog.w(TAG, "Exception when starting activity "                        + r.intent.getComponent().flattenToShortString(), e);            }            // If a dead object exception was thrown -- fall through to            // restart the application.        }        //对应的进程不存在的情况下,首先启动进程        mService.startProcessLocked(r.processName, r.info.applicationInfo, true, 0,                "activity", r.intent.getComponent(), false, false, true);    }  
  final boolean realStartActivityLocked(ActivityRecord r, ProcessRecord app,     boolean andResume, boolean checkConfig) throws RemoteException {                 app.thread.scheduleLaunchActivity(new Intent(r.intent), r.appToken,             System.identityHashCode(r), r.info, new Configuration(mService.mConfiguration),             new Configuration(task.mOverrideConfig), r.compat, r.launchedFromPackage,             task.voiceInteractor, app.repProcState, r.icicle, r.persistentState, results,             newIntents, !andResume, mService.isNextTransitionForward(), profilerInfo);  }

由框架传给了ActivityThread(代表了应用程序)

        public final void scheduleLaunchActivity(Intent intent, IBinder token, int ident,                ActivityInfo info, Configuration curConfig, Configuration overrideConfig,                CompatibilityInfo compatInfo, String referrer, IVoiceInteractor voiceInteractor,                int procState, Bundle state, PersistableBundle persistentState,                List<ResultInfo> pendingResults, List<ReferrerIntent> pendingNewIntents,                boolean notResumed, boolean isForward, ProfilerInfo profilerInfo) {            updateProcessState(procState, false);            ActivityClientRecord r = new ActivityClientRecord();            //传递给了ActivityThread的token,这个token就是IApplicationToken.Stub的代理            r.token = token;

步骤四
当ActivityThread把对应的步骤三中的r.token通过addWindow传递给WMS,然后在WMS中进行身份的验证

WMS:

    public int addWindow(Session session, IWindow client, int seq,            WindowManager.LayoutParams attrs, int viewVisibility, int displayId,            Rect outContentInsets, Rect outStableInsets, Rect outOutsets,            InputChannel outInputChannel) {            //attrs这个是应用程序ActivityClientRecord中传递过来的参数,其中的attrs.token就是步骤三种的r.token            WindowToken token = mTokenMap.get(attrs.token);            if (token == null) {                if (type >= FIRST_APPLICATION_WINDOW && type <= LAST_APPLICATION_WINDOW) {                    Slog.w(TAG_WM, "Attempted to add application window with unknown token "                          + attrs.token + ".  Aborting.");                    //这里进行token的身份验证,如果应用程序没有在mTokenMap中找到,则验证失败                    //应用程序的在WMS中的token是在步骤二创建的,必须存在,否则会报错                    return WindowManagerGlobal.ADD_BAD_APP_TOKEN;                }            }

以上四个步骤就是应用程序的token的验证过程。(其中应用窗口,输入法窗口,壁纸窗口都是类似的)
如果是其他的系统窗口token就是WMS自己创建的,不需要进行验证了。