Merge "Add support for SELF_SCAN_ONLY providers" into udc-dev

This commit is contained in:
Santiago Seifert
2023-05-26 17:14:12 +00:00
committed by Android (Google) Code Review
6 changed files with 100 additions and 35 deletions

View File

@@ -80,6 +80,18 @@ public abstract class MediaRoute2ProviderService extends Service {
@SdkConstant(SdkConstant.SdkConstantType.SERVICE_ACTION)
public static final String SERVICE_INTERFACE = "android.media.MediaRoute2ProviderService";
/**
* A category indicating that the associated provider is only intended for use within the app
* that hosts the provider.
*
* <p>Declaring this category helps the system save resources by avoiding the launch of services
* whose routes are known to be private to the app that provides them.
*
* @hide
*/
public static final String CATEGORY_SELF_SCAN_ONLY =
"android.media.MediaRoute2ProviderService.SELF_SCAN_ONLY";
/**
* The request ID to pass {@link #notifySessionCreated(long, RoutingSessionInfo)}
* when {@link MediaRoute2ProviderService} created a session although there was no creation

View File

@@ -31,6 +31,7 @@ import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.Set;
abstract class MediaRoute2Provider {
final ComponentName mComponentName;
@@ -56,7 +57,9 @@ abstract class MediaRoute2Provider {
public abstract void requestCreateSession(long requestId, String packageName, String routeId,
@Nullable Bundle sessionHints);
public abstract void releaseSession(long requestId, String sessionId);
public abstract void updateDiscoveryPreference(RouteDiscoveryPreference discoveryPreference);
public abstract void updateDiscoveryPreference(
Set<String> activelyScanningPackages, RouteDiscoveryPreference discoveryPreference);
public abstract void selectRoute(long requestId, String sessionId, String routeId);
public abstract void deselectRoute(long requestId, String sessionId, String routeId);

View File

@@ -49,6 +49,7 @@ import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Objects;
import java.util.Set;
/**
* Maintains a connection to a particular {@link MediaRoute2ProviderService}.
@@ -61,6 +62,7 @@ final class MediaRoute2ProviderServiceProxy extends MediaRoute2Provider
private final Context mContext;
private final int mUserId;
private final Handler mHandler;
private final boolean mIsSelfScanOnlyProvider;
// Connection state
private boolean mRunning;
@@ -70,14 +72,19 @@ final class MediaRoute2ProviderServiceProxy extends MediaRoute2Provider
private boolean mIsManagerScanning;
private RouteDiscoveryPreference mLastDiscoveryPreference = null;
private boolean mLastDiscoveryPreferenceIncludesThisPackage = false;
@GuardedBy("mLock")
final List<RoutingSessionInfo> mReleasingSessions = new ArrayList<>();
MediaRoute2ProviderServiceProxy(@NonNull Context context, @NonNull ComponentName componentName,
MediaRoute2ProviderServiceProxy(
@NonNull Context context,
@NonNull ComponentName componentName,
boolean isSelfScanOnlyProvider,
int userId) {
super(componentName);
mContext = Objects.requireNonNull(context, "Context must not be null.");
mIsSelfScanOnlyProvider = isSelfScanOnlyProvider;
mUserId = userId;
mHandler = new Handler(Looper.myLooper());
}
@@ -107,8 +114,11 @@ final class MediaRoute2ProviderServiceProxy extends MediaRoute2Provider
}
@Override
public void updateDiscoveryPreference(RouteDiscoveryPreference discoveryPreference) {
public void updateDiscoveryPreference(
Set<String> activelyScanningPackages, RouteDiscoveryPreference discoveryPreference) {
mLastDiscoveryPreference = discoveryPreference;
mLastDiscoveryPreferenceIncludesThisPackage =
activelyScanningPackages.contains(mComponentName.getPackageName());
if (mConnectionReady) {
mActiveConnection.updateDiscoveryPreference(discoveryPreference);
}
@@ -209,11 +219,15 @@ final class MediaRoute2ProviderServiceProxy extends MediaRoute2Provider
private boolean shouldBind() {
if (mRunning) {
// Bind when there is a discovery preference or an active route session.
return (mLastDiscoveryPreference != null
&& !mLastDiscoveryPreference.getPreferredFeatures().isEmpty())
|| !getSessionInfos().isEmpty()
|| mIsManagerScanning;
boolean shouldBind =
mLastDiscoveryPreference != null
&& !mLastDiscoveryPreference.getPreferredFeatures().isEmpty();
if (mIsSelfScanOnlyProvider) {
shouldBind &= mLastDiscoveryPreferenceIncludesThisPackage;
}
shouldBind |= mIsManagerScanning;
shouldBind |= !getSessionInfos().isEmpty();
return shouldBind;
}
return false;
}
@@ -301,7 +315,11 @@ final class MediaRoute2ProviderServiceProxy extends MediaRoute2Provider
if (mActiveConnection == connection) {
mConnectionReady = true;
if (mLastDiscoveryPreference != null) {
updateDiscoveryPreference(mLastDiscoveryPreference);
updateDiscoveryPreference(
mLastDiscoveryPreferenceIncludesThisPackage
? Set.of(mComponentName.getPackageName())
: Set.of(),
mLastDiscoveryPreference);
}
}
}

View File

@@ -16,6 +16,8 @@
package com.android.server.media;
import static android.content.pm.PackageManager.GET_RESOLVED_FILTER;
import android.annotation.NonNull;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
@@ -34,6 +36,7 @@ import android.util.Slog;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
/**
* Watches changes of packages, or scan them for finding media route providers.
@@ -41,8 +44,8 @@ import java.util.Collections;
final class MediaRoute2ProviderWatcher {
private static final String TAG = "MR2ProviderWatcher";
private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
private static final PackageManager.ResolveInfoFlags RESOLVE_INFO_FLAGS_NONE =
PackageManager.ResolveInfoFlags.of(0);
private static final PackageManager.ResolveInfoFlags RESOLVE_INFO_FLAGS =
PackageManager.ResolveInfoFlags.of(GET_RESOLVED_FILTER);
private final Context mContext;
private final Callback mCallback;
@@ -118,16 +121,26 @@ final class MediaRoute2ProviderWatcher {
int targetIndex = 0;
Intent intent = new Intent(MediaRoute2ProviderService.SERVICE_INTERFACE);
for (ResolveInfo resolveInfo :
mPackageManager.queryIntentServicesAsUser(
intent, RESOLVE_INFO_FLAGS_NONE, mUserId)) {
mPackageManager.queryIntentServicesAsUser(intent, RESOLVE_INFO_FLAGS, mUserId)) {
ServiceInfo serviceInfo = resolveInfo.serviceInfo;
if (serviceInfo != null) {
boolean isSelfScanOnlyProvider = false;
Iterator<String> categoriesIterator = resolveInfo.filter.categoriesIterator();
if (categoriesIterator != null) {
while (categoriesIterator.hasNext()) {
isSelfScanOnlyProvider |=
MediaRoute2ProviderService.CATEGORY_SELF_SCAN_ONLY.equals(
categoriesIterator.next());
}
}
int sourceIndex = findProvider(serviceInfo.packageName, serviceInfo.name);
if (sourceIndex < 0) {
MediaRoute2ProviderServiceProxy proxy =
new MediaRoute2ProviderServiceProxy(mContext,
new ComponentName(serviceInfo.packageName, serviceInfo.name),
mUserId);
new MediaRoute2ProviderServiceProxy(
mContext,
new ComponentName(serviceInfo.packageName, serviceInfo.name),
isSelfScanOnlyProvider,
mUserId);
proxy.start();
mProxies.add(targetIndex++, proxy);
mCallback.onAddProviderService(proxy);

View File

@@ -1478,6 +1478,7 @@ class MediaRouter2ServiceImpl {
final ArrayList<RouterRecord> mRouterRecords = new ArrayList<>();
final ArrayList<ManagerRecord> mManagerRecords = new ArrayList<>();
RouteDiscoveryPreference mCompositeDiscoveryPreference = RouteDiscoveryPreference.EMPTY;
Set<String> mActivelyScanningPackages = Set.of();
final UserHandler mHandler;
UserRecord(int userId) {
@@ -1525,7 +1526,12 @@ class MediaRouter2ServiceImpl {
pw.println(indent + "<no manager records>");
}
mCompositeDiscoveryPreference.dump(pw, indent);
pw.println(indent + "Composite discovery preference:");
mCompositeDiscoveryPreference.dump(pw, indent + " ");
pw.println(
indent
+ "Packages actively scanning: "
+ String.join(", ", mActivelyScanningPackages));
if (!mHandler.runWithScissors(() -> mHandler.dump(pw, indent), 1000)) {
pw.println(indent + "<could not dump handler state>");
@@ -1834,7 +1840,9 @@ class MediaRouter2ServiceImpl {
public void onAddProviderService(@NonNull MediaRoute2ProviderServiceProxy proxy) {
proxy.setCallback(this);
mRouteProviders.add(proxy);
proxy.updateDiscoveryPreference(mUserRecord.mCompositeDiscoveryPreference);
proxy.updateDiscoveryPreference(
mUserRecord.mActivelyScanningPackages,
mUserRecord.mCompositeDiscoveryPreference);
}
@Override
@@ -2341,8 +2349,8 @@ class MediaRouter2ServiceImpl {
return;
}
notifySessionInfoChangedToRouters(getRouterRecords(true), sessionInfo);
notifySessionInfoChangedToRouters(getRouterRecords(false),
mSystemProvider.getDefaultSessionInfo());
notifySessionInfoChangedToRouters(
getRouterRecords(false), mSystemProvider.getDefaultSessionInfo());
return;
}
@@ -2711,8 +2719,8 @@ class MediaRouter2ServiceImpl {
if (service == null) {
return;
}
List<RouteDiscoveryPreference> discoveryPreferences = Collections.emptyList();
List<RouterRecord> routerRecords = getRouterRecords();
List<RouterRecord> activeRouterRecords = Collections.emptyList();
List<RouterRecord> allRouterRecords = getRouterRecords();
List<ManagerRecord> managerRecords = getManagerRecords();
boolean isManagerScanning = false;
@@ -2723,15 +2731,16 @@ class MediaRouter2ServiceImpl {
<= sPackageImportanceForScanning);
if (isManagerScanning) {
discoveryPreferences = routerRecords.stream()
.map(record -> record.mDiscoveryPreference)
.collect(Collectors.toList());
activeRouterRecords = allRouterRecords;
} else {
discoveryPreferences = routerRecords.stream().filter(record ->
service.mActivityManager.getPackageImportance(record.mPackageName)
<= sPackageImportanceForScanning)
.map(record -> record.mDiscoveryPreference)
.collect(Collectors.toList());
activeRouterRecords =
allRouterRecords.stream()
.filter(
record ->
service.mActivityManager.getPackageImportance(
record.mPackageName)
<= sPackageImportanceForScanning)
.collect(Collectors.toList());
}
}
@@ -2748,22 +2757,30 @@ class MediaRouter2ServiceImpl {
// to query route providers once to obtain all of the routes of interest, which
// can be subsequently filtered for the individual discovery preferences.
Set<String> preferredFeatures = new HashSet<>();
Set<String> activelyScanningPackages = new HashSet<>();
boolean activeScan = false;
for (RouteDiscoveryPreference preference : discoveryPreferences) {
for (RouterRecord activeRouterRecord : activeRouterRecords) {
RouteDiscoveryPreference preference = activeRouterRecord.mDiscoveryPreference;
preferredFeatures.addAll(preference.getPreferredFeatures());
activeScan |= preference.shouldPerformActiveScan();
if (preference.shouldPerformActiveScan()) {
activeScan = true;
activelyScanningPackages.add(activeRouterRecord.mPackageName);
}
}
RouteDiscoveryPreference newPreference = new RouteDiscoveryPreference.Builder(
List.copyOf(preferredFeatures), activeScan || isManagerScanning).build();
synchronized (service.mLock) {
if (newPreference.equals(mUserRecord.mCompositeDiscoveryPreference)) {
if (newPreference.equals(mUserRecord.mCompositeDiscoveryPreference)
&& activelyScanningPackages.equals(mUserRecord.mActivelyScanningPackages)) {
return;
}
mUserRecord.mCompositeDiscoveryPreference = newPreference;
mUserRecord.mActivelyScanningPackages = activelyScanningPackages;
}
for (MediaRoute2Provider provider : mRouteProviders) {
provider.updateDiscoveryPreference(mUserRecord.mCompositeDiscoveryPreference);
provider.updateDiscoveryPreference(
activelyScanningPackages, mUserRecord.mCompositeDiscoveryPreference);
}
}

View File

@@ -42,6 +42,7 @@ import com.android.internal.annotations.GuardedBy;
import java.util.List;
import java.util.Objects;
import java.util.Set;
/**
* Provides routes for local playbacks such as phone speaker, wired headset, or Bluetooth speakers.
@@ -196,7 +197,8 @@ class SystemMediaRoute2Provider extends MediaRoute2Provider {
}
@Override
public void updateDiscoveryPreference(RouteDiscoveryPreference discoveryPreference) {
public void updateDiscoveryPreference(
Set<String> activelyScanningPackages, RouteDiscoveryPreference discoveryPreference) {
// Do nothing
}