Loading services/core/java/com/android/server/media/MediaSessionService.java +98 −11 Original line number Diff line number Diff line Loading @@ -29,6 +29,7 @@ import android.content.ComponentName; import android.content.ContentResolver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.content.pm.PackageManager; import android.content.pm.PackageManager.NameNotFoundException; import android.content.pm.ResolveInfo; Loading Loading @@ -76,6 +77,7 @@ import android.util.SparseIntArray; import android.view.KeyEvent; import android.view.ViewConfiguration; import com.android.internal.os.BackgroundThread; import com.android.internal.util.DumpUtils; import com.android.server.SystemService; import com.android.server.Watchdog; Loading Loading @@ -180,9 +182,8 @@ public class MediaSessionService extends SystemService implements Monitor { updateUser(); registerPackageBroadcastReceivers(); // TODO(jaewan): Query per users // TODO(jaewan): Add listener to know changes in list of services. // Refer TvInputManagerService.registerBroadcastReceivers() buildMediaSessionService2List(); } Loading Loading @@ -437,12 +438,74 @@ public class MediaSessionService extends SystemService implements Monitor { mHandler.postSessionsChanged(session.getUserId()); } private void registerPackageBroadcastReceivers() { // TODO(jaewan): Only consider changed packages when building session service list // when we make this multi-user aware. At that time, // use PackageMonitor.getChangingUserId() to know which user has changed. IntentFilter filter = new IntentFilter(); filter.addDataScheme("package"); filter.addAction(Intent.ACTION_PACKAGE_ADDED); filter.addAction(Intent.ACTION_PACKAGE_REMOVED); filter.addAction(Intent.ACTION_PACKAGE_CHANGED); filter.addAction(Intent.ACTION_PACKAGES_SUSPENDED); filter.addAction(Intent.ACTION_PACKAGES_UNSUSPENDED); filter.addAction(Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE); filter.addAction(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE); filter.addAction(Intent.ACTION_PACKAGE_REPLACED); getContext().registerReceiverAsUser(new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { final int changeUserId = intent.getIntExtra( Intent.EXTRA_USER_HANDLE, UserHandle.USER_NULL); if (changeUserId == UserHandle.USER_NULL) { Log.w(TAG, "Intent broadcast does not contain user handle: "+ intent); return; } // Check if the package is replacing (i.e. reinstalling) final boolean isReplacing = intent.getBooleanExtra(Intent.EXTRA_REPLACING, false); // TODO(jaewan): Add multi-user support with this. // final int uid = intent.getIntExtra(Intent.EXTRA_UID, 0); if (DEBUG) { Log.d(TAG, "Received change in packages, intent=" + intent); } switch (intent.getAction()) { case Intent.ACTION_PACKAGE_ADDED: case Intent.ACTION_PACKAGE_REMOVED: case Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE: case Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE: if (isReplacing) { // Ignore if the package(s) are replacing. In that case, followings will // happen in order. // 1. ACTION_PACKAGE_REMOVED with isReplacing=true // 2. ACTION_PACKAGE_ADDED with isReplacing=true // 3. ACTION_PACKAGE_REPLACED // (Note that ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE and // ACTION_EXTERNAL_APPLICATIONS_AVAILABLE will be also called with // isReplacing=true for both ASEC hosted packages and packages in // external storage) // Since we only want to update session service list once, ignore // actions above when replacing. // Replacing will be handled only once with the ACTION_PACKAGE_REPLACED. break; } // pass-through case Intent.ACTION_PACKAGE_CHANGED: case Intent.ACTION_PACKAGES_SUSPENDED: case Intent.ACTION_PACKAGES_UNSUSPENDED: case Intent.ACTION_PACKAGE_REPLACED: buildMediaSessionService2List(); } } }, UserHandle.ALL, filter, null, BackgroundThread.getHandler()); } private void buildMediaSessionService2List() { if (DEBUG) { Log.d(TAG, "buildMediaSessionService2List"); } // TODO(jaewan): Query per users. // TODO(jaewan): Also query for managed profile users. // TODO(jaewan): Similar codes are also at the updatable. Can't we share codes? PackageManager manager = getContext().getPackageManager(); List<ResolveInfo> services = new ArrayList<>(); Loading @@ -458,9 +521,13 @@ public class MediaSessionService extends SystemService implements Monitor { services.addAll(sessionServices); } synchronized (mLock) { mSessions.clear(); if (services == null) { return; // List to keep the session services that need be removed because they don't exist // in the 'services' above. List<MediaSession2Record> removeCandidates = new ArrayList<>(); for (int i = 0; i < mSessions.size(); i++) { if (mSessions.get(i).getToken().getType() != TYPE_SESSION) { removeCandidates.add(mSessions.get(i)); } } for (int i = 0; i < services.size(); i++) { if (services.get(i) == null || services.get(i).serviceInfo == null) { Loading @@ -475,17 +542,35 @@ public class MediaSessionService extends SystemService implements Monitor { } catch (NameNotFoundException e) { continue; } SessionToken2 token; try { SessionToken2 token = new SessionToken2(getContext(), token = new SessionToken2(getContext(), serviceInfo.packageName, serviceInfo.name, uid); } catch (IllegalArgumentException e) { Log.w(TAG, "Invalid session service", e); continue; } boolean found = false; for (int j = 0; j < mSessions.size(); j++) { if (token.equals(mSessions.get(j).getToken())) { // If the token already exists, keep it in the mSessions. removeCandidates.remove(mSessions.get(j)); found = true; break; } } if (!found) { // New session service is found. MediaSession2Record record = new MediaSession2Record(getContext(), token, mSessionDestroyedListener); mSessions.add(record); } catch (IllegalArgumentException e) { Log.d(TAG, "Invalid session service", e); } } for (int i = 0; i < removeCandidates.size(); i++) { removeCandidates.get(i).onSessionDestroyed(); mSessions.remove(removeCandidates.get(i)); } removeCandidates.clear(); } if (DEBUG) { Log.d(TAG, "Found " + mSessions.size() + " session services"); Loading Loading @@ -1503,12 +1588,14 @@ public class MediaSessionService extends SystemService implements Monitor { return tokens; } // TODO(jaewan): Protect this API with permission @Override public void addSessionTokensListener(ISessionTokensListener listener, int userId, String packageName) { // TODO(jaewan): Implement. } // TODO(jaewan): Protect this API with permission @Override public void removeSessionTokensListener(ISessionTokensListener listener) { // TODO(jaewan): Implement Loading Loading
services/core/java/com/android/server/media/MediaSessionService.java +98 −11 Original line number Diff line number Diff line Loading @@ -29,6 +29,7 @@ import android.content.ComponentName; import android.content.ContentResolver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.content.pm.PackageManager; import android.content.pm.PackageManager.NameNotFoundException; import android.content.pm.ResolveInfo; Loading Loading @@ -76,6 +77,7 @@ import android.util.SparseIntArray; import android.view.KeyEvent; import android.view.ViewConfiguration; import com.android.internal.os.BackgroundThread; import com.android.internal.util.DumpUtils; import com.android.server.SystemService; import com.android.server.Watchdog; Loading Loading @@ -180,9 +182,8 @@ public class MediaSessionService extends SystemService implements Monitor { updateUser(); registerPackageBroadcastReceivers(); // TODO(jaewan): Query per users // TODO(jaewan): Add listener to know changes in list of services. // Refer TvInputManagerService.registerBroadcastReceivers() buildMediaSessionService2List(); } Loading Loading @@ -437,12 +438,74 @@ public class MediaSessionService extends SystemService implements Monitor { mHandler.postSessionsChanged(session.getUserId()); } private void registerPackageBroadcastReceivers() { // TODO(jaewan): Only consider changed packages when building session service list // when we make this multi-user aware. At that time, // use PackageMonitor.getChangingUserId() to know which user has changed. IntentFilter filter = new IntentFilter(); filter.addDataScheme("package"); filter.addAction(Intent.ACTION_PACKAGE_ADDED); filter.addAction(Intent.ACTION_PACKAGE_REMOVED); filter.addAction(Intent.ACTION_PACKAGE_CHANGED); filter.addAction(Intent.ACTION_PACKAGES_SUSPENDED); filter.addAction(Intent.ACTION_PACKAGES_UNSUSPENDED); filter.addAction(Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE); filter.addAction(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE); filter.addAction(Intent.ACTION_PACKAGE_REPLACED); getContext().registerReceiverAsUser(new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { final int changeUserId = intent.getIntExtra( Intent.EXTRA_USER_HANDLE, UserHandle.USER_NULL); if (changeUserId == UserHandle.USER_NULL) { Log.w(TAG, "Intent broadcast does not contain user handle: "+ intent); return; } // Check if the package is replacing (i.e. reinstalling) final boolean isReplacing = intent.getBooleanExtra(Intent.EXTRA_REPLACING, false); // TODO(jaewan): Add multi-user support with this. // final int uid = intent.getIntExtra(Intent.EXTRA_UID, 0); if (DEBUG) { Log.d(TAG, "Received change in packages, intent=" + intent); } switch (intent.getAction()) { case Intent.ACTION_PACKAGE_ADDED: case Intent.ACTION_PACKAGE_REMOVED: case Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE: case Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE: if (isReplacing) { // Ignore if the package(s) are replacing. In that case, followings will // happen in order. // 1. ACTION_PACKAGE_REMOVED with isReplacing=true // 2. ACTION_PACKAGE_ADDED with isReplacing=true // 3. ACTION_PACKAGE_REPLACED // (Note that ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE and // ACTION_EXTERNAL_APPLICATIONS_AVAILABLE will be also called with // isReplacing=true for both ASEC hosted packages and packages in // external storage) // Since we only want to update session service list once, ignore // actions above when replacing. // Replacing will be handled only once with the ACTION_PACKAGE_REPLACED. break; } // pass-through case Intent.ACTION_PACKAGE_CHANGED: case Intent.ACTION_PACKAGES_SUSPENDED: case Intent.ACTION_PACKAGES_UNSUSPENDED: case Intent.ACTION_PACKAGE_REPLACED: buildMediaSessionService2List(); } } }, UserHandle.ALL, filter, null, BackgroundThread.getHandler()); } private void buildMediaSessionService2List() { if (DEBUG) { Log.d(TAG, "buildMediaSessionService2List"); } // TODO(jaewan): Query per users. // TODO(jaewan): Also query for managed profile users. // TODO(jaewan): Similar codes are also at the updatable. Can't we share codes? PackageManager manager = getContext().getPackageManager(); List<ResolveInfo> services = new ArrayList<>(); Loading @@ -458,9 +521,13 @@ public class MediaSessionService extends SystemService implements Monitor { services.addAll(sessionServices); } synchronized (mLock) { mSessions.clear(); if (services == null) { return; // List to keep the session services that need be removed because they don't exist // in the 'services' above. List<MediaSession2Record> removeCandidates = new ArrayList<>(); for (int i = 0; i < mSessions.size(); i++) { if (mSessions.get(i).getToken().getType() != TYPE_SESSION) { removeCandidates.add(mSessions.get(i)); } } for (int i = 0; i < services.size(); i++) { if (services.get(i) == null || services.get(i).serviceInfo == null) { Loading @@ -475,17 +542,35 @@ public class MediaSessionService extends SystemService implements Monitor { } catch (NameNotFoundException e) { continue; } SessionToken2 token; try { SessionToken2 token = new SessionToken2(getContext(), token = new SessionToken2(getContext(), serviceInfo.packageName, serviceInfo.name, uid); } catch (IllegalArgumentException e) { Log.w(TAG, "Invalid session service", e); continue; } boolean found = false; for (int j = 0; j < mSessions.size(); j++) { if (token.equals(mSessions.get(j).getToken())) { // If the token already exists, keep it in the mSessions. removeCandidates.remove(mSessions.get(j)); found = true; break; } } if (!found) { // New session service is found. MediaSession2Record record = new MediaSession2Record(getContext(), token, mSessionDestroyedListener); mSessions.add(record); } catch (IllegalArgumentException e) { Log.d(TAG, "Invalid session service", e); } } for (int i = 0; i < removeCandidates.size(); i++) { removeCandidates.get(i).onSessionDestroyed(); mSessions.remove(removeCandidates.get(i)); } removeCandidates.clear(); } if (DEBUG) { Log.d(TAG, "Found " + mSessions.size() + " session services"); Loading Loading @@ -1503,12 +1588,14 @@ public class MediaSessionService extends SystemService implements Monitor { return tokens; } // TODO(jaewan): Protect this API with permission @Override public void addSessionTokensListener(ISessionTokensListener listener, int userId, String packageName) { // TODO(jaewan): Implement. } // TODO(jaewan): Protect this API with permission @Override public void removeSessionTokensListener(ISessionTokensListener listener) { // TODO(jaewan): Implement Loading