Merge changes from topic "cherrypick_work_profile_fix" into tm-qpr-dev

* changes:
  Add support for profiles in MediaRouterService
  Use UserSwitchObserver to detect switches in the running user
This commit is contained in:
TreeHugger Robot
2022-11-16 02:34:46 +00:00
committed by Android (Google) Code Review
2 changed files with 109 additions and 60 deletions

View File

@@ -58,6 +58,8 @@ import android.util.SparseArray;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.util.function.pooled.PooledLambda;
import com.android.server.LocalServices;
import com.android.server.pm.UserManagerInternal;
import java.io.PrintWriter;
import java.lang.ref.WeakReference;
@@ -87,6 +89,7 @@ class MediaRouter2ServiceImpl {
private static final int PACKAGE_IMPORTANCE_FOR_DISCOVERY = IMPORTANCE_FOREGROUND_SERVICE;
private final Context mContext;
private final UserManagerInternal mUserManagerInternal;
private final Object mLock = new Object();
final AtomicInteger mNextRouterOrManagerId = new AtomicInteger(1);
final ActivityManager mActivityManager;
@@ -99,7 +102,7 @@ class MediaRouter2ServiceImpl {
@GuardedBy("mLock")
private final ArrayMap<IBinder, ManagerRecord> mAllManagerRecords = new ArrayMap<>();
@GuardedBy("mLock")
private int mCurrentUserId = -1;
private int mCurrentActiveUserId = -1;
private final ActivityManager.OnUidImportanceListener mOnUidImportanceListener =
(uid, importance) -> {
@@ -125,12 +128,13 @@ class MediaRouter2ServiceImpl {
}
};
MediaRouter2ServiceImpl(Context context) {
/* package */ MediaRouter2ServiceImpl(Context context) {
mContext = context;
mActivityManager = mContext.getSystemService(ActivityManager.class);
mActivityManager.addOnUidImportanceListener(mOnUidImportanceListener,
PACKAGE_IMPORTANCE_FOR_DISCOVERY);
mPowerManager = mContext.getSystemService(PowerManager.class);
mUserManagerInternal = LocalServices.getService(UserManagerInternal.class);
IntentFilter screenOnOffIntentFilter = new IntentFilter();
screenOnOffIntentFilter.addAction(ACTION_SCREEN_ON);
@@ -601,25 +605,23 @@ class MediaRouter2ServiceImpl {
}
}
//TODO(b/136703681): Review this is handling multi-user properly.
void switchUser() {
/* package */ void updateRunningUserAndProfiles(int newActiveUserId) {
synchronized (mLock) {
int userId = ActivityManager.getCurrentUser();
if (mCurrentUserId != userId) {
final int oldUserId = mCurrentUserId;
mCurrentUserId = userId; // do this first
UserRecord oldUser = mUserRecords.get(oldUserId);
if (oldUser != null) {
oldUser.mHandler.sendMessage(
obtainMessage(UserHandler::stop, oldUser.mHandler));
disposeUserIfNeededLocked(oldUser); // since no longer current user
}
UserRecord newUser = mUserRecords.get(userId);
if (newUser != null) {
newUser.mHandler.sendMessage(
obtainMessage(UserHandler::start, newUser.mHandler));
if (mCurrentActiveUserId != newActiveUserId) {
mCurrentActiveUserId = newActiveUserId;
for (int i = 0; i < mUserRecords.size(); i++) {
int userId = mUserRecords.keyAt(i);
UserRecord userRecord = mUserRecords.valueAt(i);
if (isUserActiveLocked(userId)) {
// userId corresponds to the active user, or one of its profiles. We
// ensure the associated structures are initialized.
userRecord.mHandler.sendMessage(
obtainMessage(UserHandler::start, userRecord.mHandler));
} else {
userRecord.mHandler.sendMessage(
obtainMessage(UserHandler::stop, userRecord.mHandler));
disposeUserIfNeededLocked(userRecord);
}
}
}
}
@@ -637,11 +639,21 @@ class MediaRouter2ServiceImpl {
}
}
/**
* Returns {@code true} if the given {@code userId} corresponds to the active user or a profile
* of the active user, returns {@code false} otherwise.
*/
@GuardedBy("mLock")
private boolean isUserActiveLocked(int userId) {
return mUserManagerInternal.getProfileParentId(userId) == mCurrentActiveUserId;
}
////////////////////////////////////////////////////////////////
//// ***Locked methods related to MediaRouter2
//// - Should have @NonNull/@Nullable on all arguments
////////////////////////////////////////////////////////////////
@GuardedBy("mLock")
private void registerRouter2Locked(@NonNull IMediaRouter2 router, int uid, int pid,
@NonNull String packageName, int userId, boolean hasConfigureWifiDisplayPermission,
boolean hasModifyAudioRoutingPermission) {
@@ -669,6 +681,7 @@ class MediaRouter2ServiceImpl {
userRecord.mHandler, routerRecord));
}
@GuardedBy("mLock")
private void unregisterRouter2Locked(@NonNull IMediaRouter2 router, boolean died) {
RouterRecord routerRecord = mAllRouterRecords.remove(router.asBinder());
if (routerRecord == null) {
@@ -891,6 +904,7 @@ class MediaRouter2ServiceImpl {
return sessionInfos;
}
@GuardedBy("mLock")
private void registerManagerLocked(@NonNull IMediaRouter2Manager manager,
int uid, int pid, @NonNull String packageName, int userId) {
final IBinder binder = manager.asBinder();
@@ -1125,13 +1139,14 @@ class MediaRouter2ServiceImpl {
//// - Should have @NonNull/@Nullable on all arguments
////////////////////////////////////////////////////////////
@GuardedBy("mLock")
private UserRecord getOrCreateUserRecordLocked(int userId) {
UserRecord userRecord = mUserRecords.get(userId);
if (userRecord == null) {
userRecord = new UserRecord(userId);
mUserRecords.put(userId, userRecord);
userRecord.init();
if (userId == mCurrentUserId) {
if (isUserActiveLocked(userId)) {
userRecord.mHandler.sendMessage(
obtainMessage(UserHandler::start, userRecord.mHandler));
}
@@ -1139,12 +1154,13 @@ class MediaRouter2ServiceImpl {
return userRecord;
}
@GuardedBy("mLock")
private void disposeUserIfNeededLocked(@NonNull UserRecord userRecord) {
// If there are no records left and the user is no longer current then go ahead
// and purge the user record and all of its associated state. If the user is current
// then leave it alone since we might be connected to a route or want to query
// the same route information again soon.
if (userRecord.mUserId != mCurrentUserId
if (!isUserActiveLocked(userRecord.mUserId)
&& userRecord.mRouterRecords.isEmpty()
&& userRecord.mManagerRecords.isEmpty()) {
if (DEBUG) {

View File

@@ -17,7 +17,9 @@
package com.android.server.media;
import android.annotation.NonNull;
import android.annotation.RequiresPermission;
import android.app.ActivityManager;
import android.app.UserSwitchObserver;
import android.bluetooth.BluetoothA2dp;
import android.bluetooth.BluetoothDevice;
import android.content.BroadcastReceiver;
@@ -61,7 +63,9 @@ import android.util.SparseArray;
import android.util.TimeUtils;
import com.android.internal.util.DumpUtils;
import com.android.server.LocalServices;
import com.android.server.Watchdog;
import com.android.server.pm.UserManagerInternal;
import java.io.FileDescriptor;
import java.io.PrintWriter;
@@ -102,9 +106,10 @@ public final class MediaRouterService extends IMediaRouterService.Stub
// State guarded by mLock.
private final Object mLock = new Object();
private final UserManagerInternal mUserManagerInternal;
private final SparseArray<UserRecord> mUserRecords = new SparseArray<>();
private final ArrayMap<IBinder, ClientRecord> mAllClientRecords = new ArrayMap<>();
private int mCurrentUserId = -1;
private int mCurrentActiveUserId = -1;
private final IAudioService mAudioService;
private final AudioPlayerStateMonitor mAudioPlayerStateMonitor;
private final Handler mHandler = new Handler();
@@ -130,6 +135,7 @@ public final class MediaRouterService extends IMediaRouterService.Stub
mBluetoothA2dpRouteId =
res.getString(com.android.internal.R.string.bluetooth_a2dp_audio_route_id);
mUserManagerInternal = LocalServices.getService(UserManagerInternal.class);
mAudioService = IAudioService.Stub.asInterface(
ServiceManager.getService(Context.AUDIO_SERVICE));
mAudioPlayerStateMonitor = AudioPlayerStateMonitor.getInstance(context);
@@ -217,18 +223,27 @@ public final class MediaRouterService extends IMediaRouterService.Stub
context.registerReceiverAsUser(mReceiver, UserHandle.ALL, intentFilter, null, null);
}
public void systemRunning() {
IntentFilter filter = new IntentFilter(Intent.ACTION_USER_SWITCHED);
mContext.registerReceiver(new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
if (intent.getAction().equals(Intent.ACTION_USER_SWITCHED)) {
switchUser();
}
}
}, filter);
switchUser();
/**
* Initializes the MediaRouter service.
*
* @throws RemoteException If an error occurs while registering the {@link UserSwitchObserver}.
*/
@RequiresPermission(
anyOf = {
"android.permission.INTERACT_ACROSS_USERS",
"android.permission.INTERACT_ACROSS_USERS_FULL"
})
public void systemRunning() throws RemoteException {
ActivityManager.getService()
.registerUserSwitchObserver(
new UserSwitchObserver() {
@Override
public void onUserSwitchComplete(int newUserId) {
updateRunningUserAndProfiles(newUserId);
}
},
TAG);
updateRunningUserAndProfiles(ActivityManager.getCurrentUser());
}
@Override
@@ -448,7 +463,7 @@ public final class MediaRouterService extends IMediaRouterService.Stub
pw.println("MEDIA ROUTER SERVICE (dumpsys media_router)");
pw.println();
pw.println("Global state");
pw.println(" mCurrentUserId=" + mCurrentUserId);
pw.println(" mCurrentUserId=" + mCurrentActiveUserId);
synchronized (mLock) {
final int count = mUserRecords.size();
@@ -702,26 +717,31 @@ public final class MediaRouterService extends IMediaRouterService.Stub
}
}
void switchUser() {
/**
* Starts all {@link UserRecord user records} associated with the active user (whose ID is
* {@code newActiveUserId}) or the active user's profiles.
*
* <p>All other records are stopped, and those without associated client records are removed.
*/
private void updateRunningUserAndProfiles(int newActiveUserId) {
synchronized (mLock) {
int userId = ActivityManager.getCurrentUser();
if (mCurrentUserId != userId) {
final int oldUserId = mCurrentUserId;
mCurrentUserId = userId; // do this first
UserRecord oldUser = mUserRecords.get(oldUserId);
if (oldUser != null) {
oldUser.mHandler.sendEmptyMessage(UserHandler.MSG_STOP);
disposeUserIfNeededLocked(oldUser); // since no longer current user
}
UserRecord newUser = mUserRecords.get(userId);
if (newUser != null) {
newUser.mHandler.sendEmptyMessage(UserHandler.MSG_START);
if (mCurrentActiveUserId != newActiveUserId) {
mCurrentActiveUserId = newActiveUserId;
for (int i = 0; i < mUserRecords.size(); i++) {
int userId = mUserRecords.keyAt(i);
UserRecord userRecord = mUserRecords.valueAt(i);
if (isUserActiveLocked(userId)) {
// userId corresponds to the active user, or one of its profiles. We
// ensure the associated structures are initialized.
userRecord.mHandler.sendEmptyMessage(UserHandler.MSG_START);
} else {
userRecord.mHandler.sendEmptyMessage(UserHandler.MSG_STOP);
disposeUserIfNeededLocked(userRecord);
}
}
}
}
mService2.switchUser();
mService2.updateRunningUserAndProfiles(newActiveUserId);
}
void clientDied(ClientRecord clientRecord) {
@@ -776,8 +796,10 @@ public final class MediaRouterService extends IMediaRouterService.Stub
clientRecord.mGroupId = groupId;
if (groupId != null) {
userRecord.addToGroup(groupId, clientRecord);
userRecord.mHandler.obtainMessage(UserHandler.MSG_NOTIFY_GROUP_ROUTE_SELECTED, groupId)
.sendToTarget();
userRecord
.mHandler
.obtainMessage(UserHandler.MSG_NOTIFY_GROUP_ROUTE_SELECTED, groupId)
.sendToTarget();
}
}
@@ -863,9 +885,13 @@ public final class MediaRouterService extends IMediaRouterService.Stub
clientRecord.mUserRecord.mClientGroupMap.get(clientRecord.mGroupId);
if (group != null) {
group.mSelectedRouteId = routeId;
clientRecord.mUserRecord.mHandler.obtainMessage(
UserHandler.MSG_NOTIFY_GROUP_ROUTE_SELECTED, clientRecord.mGroupId)
.sendToTarget();
clientRecord
.mUserRecord
.mHandler
.obtainMessage(
UserHandler.MSG_NOTIFY_GROUP_ROUTE_SELECTED,
clientRecord.mGroupId)
.sendToTarget();
}
}
}
@@ -897,7 +923,7 @@ public final class MediaRouterService extends IMediaRouterService.Stub
if (DEBUG) {
Slog.d(TAG, userRecord + ": Initialized");
}
if (userRecord.mUserId == mCurrentUserId) {
if (isUserActiveLocked(userRecord.mUserId)) {
userRecord.mHandler.sendEmptyMessage(UserHandler.MSG_START);
}
}
@@ -907,8 +933,7 @@ public final class MediaRouterService extends IMediaRouterService.Stub
// and purge the user record and all of its associated state. If the user is current
// then leave it alone since we might be connected to a route or want to query
// the same route information again soon.
if (userRecord.mUserId != mCurrentUserId
&& userRecord.mClientRecords.isEmpty()) {
if (!isUserActiveLocked(userRecord.mUserId) && userRecord.mClientRecords.isEmpty()) {
if (DEBUG) {
Slog.d(TAG, userRecord + ": Disposed");
}
@@ -917,6 +942,14 @@ public final class MediaRouterService extends IMediaRouterService.Stub
}
}
/**
* Returns {@code true} if the given {@code userId} corresponds to the active user or a profile
* of the active user, returns {@code false} otherwise.
*/
private boolean isUserActiveLocked(int userId) {
return mUserManagerInternal.getProfileParentId(userId) == mCurrentActiveUserId;
}
private void initializeClientLocked(ClientRecord clientRecord) {
if (DEBUG) {
Slog.d(TAG, clientRecord + ": Registered");