if (sSystemServicesProxy.isSystemUser(processUser)) { // For the system user, initialize an instance of the interface that we can pass to the // secondary user mSystemToUserCallbacks = newRecentsSystemUser(mContext, mImpl); } else { // For the secondary user, bind to the primary user's service to get a persistent // interface to register its implementation and to later update its state registerWithSystemUser(); }
/** * An implementation of the system user's Recents interface to be called remotely by secondary * users. */ publicclassRecentsSystemUserextendsIRecentsSystemUserCallbacks.Stub {
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
package com.android.systemui.recents;
import android.graphics.Rect;
/** * Due to the fact that RecentsActivity is per-user, we need to establish an * interface (this) for the non-system user to register itself for callbacks and to * callback to the system user to update internal state. */ oneway interfaceIRecentsSystemUserCallbacks { voidregisterNonSystemUserCallbacks(IBinder nonSystemUserCallbacks, int userId);
voidupdateRecentsVisibility(boolean visible); voidstartScreenPinning(int taskId); voidsendRecentsDrawnEvent(); voidsendDockingTopTaskEvent(int dragMode, in Rect initialRect); voidsendLaunchRecentsEvent(); }
/** * A strictly system-user service that is started by the secondary user's Recents (with a limited * lifespan), to get the interface that the secondary user's Recents can call through to the system * user's Recents. */ publicclassRecentsSystemUserServiceextendsService {
if (Intent.ACTION_USER_SWITCHED.equals(intent.getAction())) { if (mExitGuestDialog != null && mExitGuestDialog.isShowing()) { mExitGuestDialog.cancel(); mExitGuestDialog = null; }
finalintcurrentId= intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -1); finalUserInfouserInfo= mUserManager.getUserInfo(currentId); finalintN= mUsers.size(); for (inti=0; i < N; i++) { UserRecordrecord= mUsers.get(i); if (record.info == null) continue; booleanshouldBeCurrent= record.info.id == currentId; if (record.isCurrent != shouldBeCurrent) { mUsers.set(i, record.copyWithIsCurrent(shouldBeCurrent)); } if (shouldBeCurrent && !record.isGuest) { mLastNonGuestUser = record.info.id; } if ((userInfo == null || !userInfo.isAdmin()) && record.isRestricted) { // Immediately remove restricted records in case the AsyncTask is too slow. mUsers.remove(i); i--; } } notifyAdapters();
// Disconnect from the old secondary user's service if (mSecondaryUser != UserHandle.USER_NULL) { context.stopServiceAsUser(mSecondaryUserServiceIntent, UserHandle.of(mSecondaryUser)); mSecondaryUser = UserHandle.USER_NULL; } // Connect to the new secondary user's service (purely to ensure that a persistent // SystemUI application is created for that user) if (userInfo != null && !userInfo.isPrimary()) { context.startServiceAsUser(mSecondaryUserServiceIntent, UserHandle.of(userInfo.id)); mSecondaryUser = userInfo.id; }
/** * The classes of the stuff to start for each user. This is a subset of the services listed * above. */ privatefinal Class<?>[] SERVICES_PER_USER = newClass[] { com.android.systemui.recents.Recents.class, com.android.systemui.tv.pip.PipUI.class };
/** * Attempts to register with the system user. */ privatevoidregisterWithSystemUser() { finalintprocessUser= sSystemServicesProxy.getProcessUser(); postToSystemUser(newRunnable() { @Override publicvoidrun() { try { mUserToSystemCallbacks.registerNonSystemUserCallbacks( newRecentsImplProxy(mImpl), processUser); } catch (RemoteException e) { Log.e(TAG, "Failed to register", e); } } }); }
/** * Runs the runnable in the system user's Recents context, connecting to the service if * necessary. */ privatevoidpostToSystemUser(final Runnable onConnectRunnable) { mOnConnectRunnables.add(onConnectRunnable); if (mUserToSystemCallbacks == null) { IntentsystemUserServiceIntent=newIntent(); systemUserServiceIntent.setClass(mContext, RecentsSystemUserService.class); booleanbound= mContext.bindServiceAsUser(systemUserServiceIntent, mUserToSystemServiceConnection, Context.BIND_AUTO_CREATE, UserHandle.SYSTEM); EventLog.writeEvent(EventLogTags.SYSUI_RECENTS_CONNECTION, EventLogConstants.SYSUI_RECENTS_CONNECTION_USER_BIND_SERVICE, sSystemServicesProxy.getProcessUser()); if (!bound) { // Retry after a fixed duration mHandler.postDelayed(newRunnable() { @Override publicvoidrun() { registerWithSystemUser(); } }, BIND_TO_SYSTEM_USER_RETRY_DELAY); } } else { runAndFlushOnConnectRunnables(); } }
/** * Runs all the queued runnables after a service connection is made. */ privatevoidrunAndFlushOnConnectRunnables() { for (Runnable r : mOnConnectRunnables) { r.run(); } mOnConnectRunnables.clear(); }
8.registerWithSystemUser这个方法的作用是与主用户空间的mSystemToUserCallbacks建立联系。先要执行 postToSystemUser方法,并且把mUserToSystemCallbacks.registerNonSystemUserCallbacks( new RecentsImplProxy(mImpl), processUser);作为一个Runnable传进去。 一点点分析吧。 这个postToSystemUser方法里,先把参数里的Runnable放到一个全局变量里,然后在mUserToSystemCallbacks不为空的时候调用runAndFlushOnConnectRunnables来把这些Runnable执行并清空。 而mUserToSystemCallbacks是在onServiceConnected里赋值的。总结起来就是绑定service后会把之前的Runnable执行并清空。而这个要绑定的服务就是主用户进程里的RecentsSystemUserService。
// Only for secondary users, this is the service connection we use to connect to the system user privatefinalServiceConnectionmUserToSystemServiceConnection=newServiceConnection() { @Override publicvoidonServiceConnected(ComponentName name, IBinder service) { if (service != null) { mUserToSystemCallbacks = IRecentsSystemUserCallbacks.Stub.asInterface( service); EventLog.writeEvent(EventLogTags.SYSUI_RECENTS_CONNECTION, EventLogConstants.SYSUI_RECENTS_CONNECTION_USER_SYSTEM_BOUND, sSystemServicesProxy.getProcessUser());
// Listen for system user's death, so that we can reconnect later try { service.linkToDeath(mUserToSystemCallbacksDeathRcpt, 0); } catch (RemoteException e) { Log.e(TAG, "Lost connection to (System) SystemUI", e); }
// Run each of the queued runnables runAndFlushOnConnectRunnables(); }
// Unbind ourselves now that we've registered our callbacks. The // binder to the system user are still valid at this point. mContext.unbindService(this); }
@Override publicvoidonServiceDisconnected(ComponentName name) { // Do nothing } };