美文网首页安卓
Activity中的token

Activity中的token

作者: android_coder | 来源:发表于2019-08-11 20:00 被阅读0次

Activity的Token对象

什么是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对象

static 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();
}

在构建ActivityRecord的时候就会创建一个Token对象,ActivityRecord持有该对象

ActivityRecord(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) {
service = _service;
appToken = new Token(this, _intent);

ActivityRecord是Activity在服务端AMS中的描述,保存了所有的activity信息,包括启动模式flag,包名,进程名

我们都知道Activity是有页面显示的,也就是窗口,wms是负责管理当前系统中所有的窗口,我们都知道activity在ams中是通过栈的形式被管理的,其实在wms中数据结构和ams是一一对应的,token有一个很重要的作用就是窗口分组的依据,我们通过这个token就能找到对应的窗口信息,在启动一个activity的过程中token是会从ams传递到wms和应用程序,我们分析下这个过程

Token从ams传递到wms的过程

我们知道在activity启动过程有会调用到ActivityStarter::startActivityUnchecked

 mTargetStack.startActivityLocked(mStartActivity, topFocused, newTask, mKeepCurTransition,
            mOptions);------------>第一个关键点
    if (mDoResume) {
        final ActivityRecord topTaskActivity =
                mStartActivity.getTask().topRunningActivityLocked();
        if (!mTargetStack.isFocusable()
                || (topTaskActivity != null && topTaskActivity.mTaskOverlay
                && mStartActivity != topTaskActivity)) {
            // If the activity is not focusable, we can't resume it, but still would like to
            // make sure it becomes visible as it starts (this will also trigger entry
            // animation). An example of this are PIP activities.
            // Also, we don't want to resume activities in a task that currently has an overlay
            // as the starting activity just needs to be in the visible paused state until the
            // over is removed.
            mTargetStack.ensureActivitiesVisibleLocked(null, 0, !PRESERVE_WINDOWS);
            // Go ahead and tell window manager to execute app transition for this activity
            // since the app transition will not be triggered through the resume channel.
            mService.mWindowManager.executeAppTransition();
        } else {
            // If the target stack was not previously focusable (previous top running activity
            // on that stack was not visible) then any prior calls to move the stack to the
            // will not update the focused stack.  If starting the new activity now allows the
            // task stack to be focusable, then ensure that we now update the focused stack
            // accordingly.
            if (mTargetStack.isFocusable() && !mSupervisor.isFocusedStack(mTargetStack)) {
                mTargetStack.moveToFront("startActivityUnchecked");
            }
            mSupervisor.resumeFocusedStackTopActivityLocked(mTargetStack, mStartActivity,
                    mOptions);------->第二个关键点
        }

ActivityStack::startActivityLocked

  // Slot the activity into the history stack and proceed
  if (DEBUG_ADD_REMOVE) Slog.i(TAG, "Adding activity " + r + " to stack to task " + task,
            new RuntimeException("here").fillInStackTrace());
  // TODO: Need to investigate if it is okay for the controller to already be created by   the
    // time we get to this point. I think it is, but need to double check.
    // Use test in b/34179495 to trace the call path.
    if (r.getWindowContainerController() == null) {
        r.createWindowContainer();------------->根据token创建AppWindowToken
   }
   task.setFrontOfTask();---------------------->将任务栈放在栈顶中

AppWindowContainerController

void createWindowContainer() {
    if (mWindowContainerController != null) {
        throw new IllegalArgumentException("Window container=" + mWindowContainerController
                + " already created for r=" + this);
    }
    inHistory = true;
    final TaskWindowContainerController taskController = task.getWindowContainerController();
    // TODO(b/36505427): Maybe this call should be moved inside updateOverrideConfiguration()
    task.updateOverrideConfigurationFromLaunchBounds();
    // Make sure override configuration is up-to-date before using to create window controller.
    updateOverrideConfiguration();
    mWindowContainerController = new AppWindowContainerController(taskController, appToken,
            this, Integer.MAX_VALUE /* add on top */, info.screenOrientation, fullscreen,
            (info.flags & FLAG_SHOW_FOR_ALL_USERS) != 0, info.configChanges,
            task.voiceSession != null, mLaunchTaskBehind, isAlwaysFocusable(),
            appInfo.targetSdkVersion, mRotationAnimationHint,
            ActivityManagerService.getInputDispatchingTimeoutLocked(this) * 1000000L);
    task.addActivityToTop(this);
    // When an activity is started directly into a split-screen fullscreen stack, we need to
    // update the initial multi-window modes so that the callbacks are scheduled correctly when
    // the user leaves that mode.
    mLastReportedMultiWindowMode = inMultiWindowMode();
    mLastReportedPictureInPictureMode = inPinnedWindowingMode();
}

public AppWindowContainerController(TaskWindowContainerController taskController,
        IApplicationToken token, AppWindowContainerListener listener, int index,
        int requestedOrientation, boolean fullscreen, boolean showForAllUsers, int configChanges,
        boolean voiceInteraction, boolean launchTaskBehind, boolean alwaysFocusable,
        int targetSdkVersion, int rotationAnimationHint, long inputDispatchingTimeoutNanos,
        WindowManagerService service) {
    super(listener, service);
    mHandler = new H(service.mH.getLooper());
    mToken = token;
    synchronized(mWindowMap) {
        AppWindowToken atoken = mRoot.getAppWindowToken(mToken.asBinder());
        if (atoken != null) {
            // TODO: Should this throw an exception instead?
            Slog.w(TAG_WM, "Attempted to add existing app token: " + mToken);
            return;
        }

        final Task task = taskController.mContainer;
        if (task == null) {
            throw new IllegalArgumentException("AppWindowContainerController: invalid "
                    + " controller=" + taskController);
        }

        atoken = createAppWindow(mService, token, voiceInteraction, task.getDisplayContent(),
                inputDispatchingTimeoutNanos, fullscreen, showForAllUsers, targetSdkVersion,
                requestedOrientation, rotationAnimationHint, configChanges, launchTaskBehind,
                alwaysFocusable, this);
        if (DEBUG_TOKEN_MOVEMENT || DEBUG_ADD_REMOVE) Slog.v(TAG_WM, "addAppToken: " + atoken
                + " controller=" + taskController + " at " + index);
        task.addChild(atoken, index);
    }
}

AppWindowToken createAppWindow(WindowManagerService service, IApplicationToken token,
        boolean voiceInteraction, DisplayContent dc, long inputDispatchingTimeoutNanos,
        boolean fullscreen, boolean showForAllUsers, int targetSdk, int orientation,
        int rotationAnimationHint, int configChanges, boolean launchTaskBehind,
        boolean alwaysFocusable, AppWindowContainerController controller) {
    return new AppWindowToken(service, token, voiceInteraction, dc,
            inputDispatchingTimeoutNanos, fullscreen, showForAllUsers, targetSdk, orientation,
            rotationAnimationHint, configChanges, launchTaskBehind, alwaysFocusable,
            controller);----------->创建AppWindowToken对象
}

首先是创建一个AppWindowContainerController的对象,其中的参数appToken就是ActivityRecord的成员变量mToken,此时ActivityRecord的mtoken对象就传递到了wms

Token从AMS传递到app端

我们继续分析activity的启动流程,我们知道在启动activity中有一步就是realStartActivityLocked

// Create activity launch transaction.
final ClientTransaction clientTransaction = ClientTransaction.obtain(app.thread,
                    r.appToken);
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.launchedFromPackage, task.voiceInteractor, app.repProcState, r.icicle,
                    r.persistentState, results, newIntents, mService.isNextTransitionForward(),
                    profilerInfo));

            // Set desired final state.
            final ActivityLifecycleItem lifecycleItem;
            if (andResume) {
                lifecycleItem = ResumeActivityItem.obtain(mService.isNextTransitionForward());
            } else {
                lifecycleItem = PauseActivityItem.obtain();
            }
 clientTransaction.setLifecycleStateRequest(lifecycleItem);
// Schedule transaction.
mService.getLifecycleManager().scheduleTransaction(clientTransaction);

void scheduleTransaction(ClientTransaction transaction) throws RemoteException {
    final IApplicationThread client = transaction.getClient();
    transaction.schedule();
    if (!(client instanceof Binder)) {
        // If client is not an instance of Binder - it's a remote call and at this point it is
        // safe to recycle the object. All objects used for local calls will be recycled after
        // the transaction is executed on client in ActivityThread.
        transaction.recycle();
    }
}

public void schedule() throws RemoteException {
    mClient.scheduleTransaction(this);
}

public void scheduleTransaction(ClientTransaction transaction) throws RemoteException {
        ActivityThread.this.scheduleTransaction(transaction);
        //
}

void scheduleTransaction(ClientTransaction transaction) {
    transaction.preExecute(this);
    sendMessage(ActivityThread.H.EXECUTE_TRANSACTION, transaction);
}

case EXECUTE_TRANSACTION:
     final ClientTransaction transaction = (ClientTransaction) msg.obj;
     mTransactionExecutor.execute(transaction);
     if (isSystem()) {
         // Client transactions inside system process are recycled on the client side
         // instead of ClientLifecycleManager to avoid being cleared before this
         // message is handled.
         transaction.recycle();
 }
 // TODO(lifecycler): Recycle locally scheduled transactions.
 break;

public void execute(ClientTransaction transaction) {
    final IBinder token = transaction.getActivityToken();
    log("Start resolving transaction for client: " + mTransactionHandler + ", token: " + token);

    executeCallbacks(transaction);

    executeLifecycleState(transaction);
    mPendingActions.clear();
    log("End resolving transaction");
}

public void executeCallbacks(ClientTransaction transaction) {
    final List<ClientTransactionItem> callbacks = transaction.getCallbacks();
    if (callbacks == null) {
        // No callbacks to execute, return early.
        return;
    }
    log("Resolving callbacks");

    final IBinder token = transaction.getActivityToken();
    ActivityClientRecord r = mTransactionHandler.getActivityClient(token);

    // In case when post-execution state of the last callback matches the final state requested
    // for the activity in this transaction, we won't do the last transition here and do it when
    // moving to final state instead (because it may contain additional parameters from server).
    final ActivityLifecycleItem finalStateRequest = transaction.getLifecycleStateRequest();
    final int finalState = finalStateRequest != null ? finalStateRequest.getTargetState()
            : UNDEFINED;
    // Index of the last callback that requests some post-execution state.
    final int lastCallbackRequestingState = lastCallbackRequestingState(transaction);

    final int size = callbacks.size();
    for (int i = 0; i < size; ++i) {
        final ClientTransactionItem item = callbacks.get(i);
        log("Resolving callback: " + item);
        final int postExecutionState = item.getPostExecutionState();
        final int closestPreExecutionState = mHelper.getClosestPreExecutionState(r,
                item.getPostExecutionState());
        if (closestPreExecutionState != UNDEFINED) {
            cycleToPath(r, closestPreExecutionState);
        }

        item.execute(mTransactionHandler, token, mPendingActions);//数据类型LaunchActivityItem
        item.postExecute(mTransactionHandler, token, mPendingActions);
        if (r == null) {
            // Launch activity request will create an activity record.
            r = mTransactionHandler.getActivityClient(token);
        }

        if (postExecutionState != UNDEFINED && r != null) {
            // Skip the very last transition and perform it by explicit state request instead.
            final boolean shouldExcludeLastTransition =
                    i == lastCallbackRequestingState && finalState == postExecutionState;
            cycleToPath(r, postExecutionState, shouldExcludeLastTransition);
        }
    }
}

LaunchActivityItem::execute
public void execute(ClientTransactionHandler client, IBinder token,
        PendingTransactionActions pendingActions) {
    Trace.traceBegin(TRACE_TAG_ACTIVITY_MANAGER, "activityStart");
    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 */);
    Trace.traceEnd(TRACE_TAG_ACTIVITY_MANAGER);
}

public Activity handleLaunchActivity(ActivityClientRecord r,
        PendingTransactionActions pendingActions, Intent customIntent) {
    // If we are getting ready to gc after going to the background, well
    // we are back active so skip it.
    unscheduleGcIdler();
    mSomeActivitiesChanged = true;
    if (r.profilerInfo != null) {
        mProfiler.setProfiler(r.profilerInfo);
        mProfiler.startProfiling();
    }
    // Make sure we are running with the most recent config.
    handleConfigurationChanged(null, null);
    if (localLOGV) Slog.v(
        TAG, "Handling launch of " + r);
    // Initialize before creating the activity
    if (!ThreadedRenderer.sRendererDisabled) {
        GraphicsEnvironment.earlyInitEGL();
    }
    WindowManagerGlobal.initialize();
    final Activity a = performLaunchActivity(r, customIntent);

private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
    ActivityInfo aInfo = r.activityInfo;
    if (r.packageInfo == null) {
        r.packageInfo = getPackageInfo(aInfo.applicationInfo, r.compatInfo,
                Context.CONTEXT_INCLUDE_CODE);
    }
    ComponentName component = r.intent.getComponent();
    if (component == null) {
        component = r.intent.resolveActivity(
            mInitialApplication.getPackageManager());
        r.intent.setComponent(component);
    }

    if (r.activityInfo.targetActivity != null) {
        component = new ComponentName(r.activityInfo.packageName,
                r.activityInfo.targetActivity);
    }
    ContextImpl appContext = createBaseContextForActivity(r);
    Activity activity = null;
    try {
        java.lang.ClassLoader cl = appContext.getClassLoader();
        activity = mInstrumentation.newActivity(
                cl, component.getClassName(), r.intent);
        StrictMode.incrementExpectedActivityCount(activity.getClass());
        r.intent.setExtrasClassLoader(cl);
        r.intent.prepareToEnterProcess();
        if (r.state != null) {
            r.state.setClassLoader(cl);
        }
    } catch (Exception e) {
        if (!mInstrumentation.onException(activity, e)) {
            throw new RuntimeException(
                "Unable to instantiate activity " + component
                + ": " + e.toString(), e);
        }
    }

    try {
        Application app = r.packageInfo.makeApplication(false, mInstrumentation);
        if (localLOGV) Slog.v(TAG, "Performing launch of " + r);
        if (localLOGV) Slog.v(
                TAG, r + ": app=" + app
                + ", appName=" + app.getPackageName()
                + ", pkg=" + r.packageInfo.getPackageName()
                + ", comp=" + r.intent.getComponent().toShortString()
                + ", dir=" + r.packageInfo.getAppDir());

        if (activity != null) {
            CharSequence title = r.activityInfo.loadLabel(appContext.getPackageManager());
            Configuration config = new Configuration(mCompatConfiguration);
            if (r.overrideConfig != null) {
                config.updateFrom(r.overrideConfig);
            }
            if (DEBUG_CONFIGURATION) Slog.v(TAG, "Launching activity "
                    + r.activityInfo.name + " with config " + config);
            Window window = null;
            if (r.mPendingRemoveWindow != null && r.mPreserveWindow) {
                window = r.mPendingRemoveWindow;
                r.mPendingRemoveWindow = null;
                r.mPendingRemoveWindowManager = null;
            }
            appContext.setOuterContext(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);

调用activity的attch方法将token传递给了activity
这样token就保存在ams,wms和app中

简单总结

过程: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的合法性。

相关文章

网友评论

    本文标题:Activity中的token

    本文链接:https://www.haomeiwen.com/subject/ipnsjctx.html