欢迎访问移动开发之家(rcyd.net),关注移动开发教程。移动开发之家  移动开发问答|  每日更新
页面位置 : > > > 内容正文

深入理解Activity——Token之旅,activitytoken,我们知道匿名Binder

来源: 开发者 投稿于  被查看 46069 次 评论:273

深入理解Activity——Token之旅,activitytoken,我们知道匿名Binder


Token是ActivityRecord的内部静态类,我们先来看下Token的继承关系, Token extends IApplicationToken.Stub,从IApplicationToken.Stub类进行继承,根据Binder的机制可以知道Token是一个匿名Binder实体类,这个匿名Binder实体会传递给其他进程,其他进程会拿到Token的代理端。

我们知道匿名Binder有两个比较重要的用途,一个是拿到Binder代理端后可跨Binder调用实体端的函数接口,另一个作用便是在多个进程中标识同一个对象。往往这两个作用是同时存在的,比如我们这里研究的Token就同时存在这两个作用,但最重要的便是后者,Token标识了一个ActivityRecord对象,即间接标识了一个Activity。

下面这个图是Token的传递,首先会传递到WMS中,接着会传递到应用进程ActivityThread中, 下面来具体分析这个传递流程。

111227jyrpvvgrvpcpo1zg.jpg

1、Token对象的创建

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, ActivityStackSupervisor supervisor,
  ActivityContainer container, Bundle options) {
        service = _service;
        appToken = new Token(this);
        ........
}

在ActivityRecord的构造函数中创建,标识着当前这个ActivityRecord,即间接代表着一个Activity。

2、AMS调用WMS的addAPPToken()接口

在启动一个Activity时,会调用startActivityLocked()来在WMS中添加一个AppWindowToken对象;

final void startActivityLocked(ActivityRecord r, boolean newTask,
  boolean doResume, boolean keepCurTransition, Bundle options) {
  ......
  mWindowManager.addAppToken(task.mActivities.indexOf(r), r.appToken,
    r.task.taskId, mStackId, r.info.screenOrientation, r.fullscreen,
    (r.info.flags & ActivityInfo.FLAG_SHOW_ON_LOCK_SCREEN) != 0, r.userId,
    r.info.configChanges, task.voiceSession != null, r.mLaunchTaskBehind);
  ......
}
public void addAppToken(int addPos, IApplicationToken token, int taskId, int stackId,
    int requestedOrientation, boolean fullscreen, boolean showWhenLocked, int userId,
    int configChanges, boolean voiceInteraction, boolean launchTaskBehind) {
    ......
  synchronized(mWindowMap) {
    AppWindowToken atoken = findAppWindowToken(token.asBinder());
    if (atoken != null) {
      Slog.w(TAG, "Attempted to add existing app token: " + token);
      return;
    }
    atoken = new AppWindowToken(this, token, voiceInteraction);
    ......
    Task task = mTaskIdToTask.get(taskId);
    if (task == null) {
      createTask(taskId, stackId, userId, atoken);
    } else {
      task.addAppToken(addPos, atoken);
    }
    mTokenMap.put(token.asBinder(), atoken);
    // Application tokens start out hidden.
    atoken.hidden = true;
    atoken.hiddenRequested = true;
    //dump();
  }
}

3、AMS跨Binder调用应用进程的 scheduleLaunchActivity()将

Token传递给上层应用进程

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),
    r.compat, r.launchedFromPackage, r.task.voiceInteractor, app.repProcState,
    r.icicle, r.persistentState, results, newIntents, !andResume,
    mService.isNextTransitionForward(), profilerInfo);
  ......
}

这个是通过调用app.thread.scheduleLaunchActivity() Binder调用完成的,可以知道对端接收到的便是Token的代理对象。

我们来看下ApplicationThread中scheduleLaunchActivity()的实现:

public final void scheduleLaunchActivity(Intent intent, IBinder token, int ident,
  ActivityInfo info, Configuration curConfig, 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();
    r.token = token;
    r.ident = ident;
    r.intent = intent;
    r.referrer = referrer;
    r.voiceInteractor = voiceInteractor;
    r.activityInfo = info;
    r.compatInfo = compatInfo;
    r.state = state;
    r.persistentState = persistentState;
    r.pendingResults = pendingResults;
    r.pendingIntents = pendingNewIntents;
    r.startsNotResumed = notResumed;
    r.isForward = isForward;
    r.profilerInfo = profilerInfo;
    updatePendingConfiguration(curConfig);
    sendMessage(H.LAUNCH_ACTIVITY, r);
}

函数中创建一个ActivityClientRecord对象,然后将Token的代理对象保存在ActivityClientRecord.token中。ActivityClientRecord也代表着一个Activity,不过是在应用进程中,而ActivityRecord是在ActivityManagerService中代表一个Activity。

4、Activity窗口添加

ViewRootImpl.setView()函数中添加Activity窗口时在参数mWindowAttributes中携带Token代理对象。

public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView) {
  synchronized (this) {
    if (mView == null) {
      mView = view;
      ......
      mWindowAttributes.copyFrom(attrs);
      ......
      try {
        ......
        res = mWindowSession.addToDisplay(mWindow, mSeq, mWindowAttributes,
            getHostVisibility(), mDisplay.getDisplayId(),
            mAttachInfo.mContentInsets, mAttachInfo.mStableInsets, mInputChannel);
      } catch (RemoteException e) {
        ......
      } finally {
        ......
      }
    ......
    }
  }
}
public int addWindow(Session session, IWindow client, int seq,
  WindowManager.LayoutParams attrs, int viewVisibility, int displayId,
  Rect outContentInsets, Rect outStableInsets, InputChannel outInputChannel) {
  ......
  boolean addToken = false;
  WindowToken token = mTokenMap.get(attrs.token);
  ......
  win = new WindowState(this, session, client, token,
    attachedWindow, appOp[0], seq, attrs, viewVisibility, displayContent);
  mWindowMap.put(client.asBinder(), win);
  ......
}

根据Binder机制可以知道从上层应用传递过来的Token代理对象会转换成SystemServer进程中的 Token代理对象,后者与 第2步中从Token对象转换成的代理对象(token.asBinder()) 是同一个对象,所以上面调用 mTokenMap.get(attrs.token)时便能返回正确返回一个WindowToken(这个WindowToken其实是一个APPWindowToken)。


作者:我是楼主

用户评论