summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author MingWei <mingweiliao@google.com> 2024-02-07 17:30:13 +0000
committer MingWei Liao <mingweiliao@google.com> 2024-02-26 13:15:02 +0000
commit449490c4a7b64801097c3a1121c11785138204aa (patch)
tree75256d189f6cb163267b070b6400b8d1c85e2d25
parent98a3f1219902f232dc744e6a90fa38cc07e61279 (diff)
Restrict RecognitionService process capabilities
Only provides certain privileged recognition service the privilege process capabilities from system server. For recognition service provided by client apps, it needs to stay in foreground in order to keep the while-in-use permission. Test: Cts Bug: 307947153 Change-Id: Idd702017c4a4f7cc63b591660b599eccfa61b956
-rw-r--r--services/core/java/com/android/server/speech/RemoteSpeechRecognitionService.java18
-rw-r--r--services/core/java/com/android/server/speech/SpeechRecognitionManagerServiceImpl.java64
2 files changed, 77 insertions, 5 deletions
diff --git a/services/core/java/com/android/server/speech/RemoteSpeechRecognitionService.java b/services/core/java/com/android/server/speech/RemoteSpeechRecognitionService.java
index bb5a697114d3..7ddb61e5ca52 100644
--- a/services/core/java/com/android/server/speech/RemoteSpeechRecognitionService.java
+++ b/services/core/java/com/android/server/speech/RemoteSpeechRecognitionService.java
@@ -68,12 +68,14 @@ final class RemoteSpeechRecognitionService extends ServiceConnector.Impl<IRecogn
private final ComponentName mComponentName;
RemoteSpeechRecognitionService(
- Context context, ComponentName serviceName, int userId, int callingUid) {
+ Context context,
+ ComponentName serviceName,
+ int userId,
+ int callingUid,
+ boolean isPrivileged) {
super(context,
new Intent(RecognitionService.SERVICE_INTERFACE).setComponent(serviceName),
- Context.BIND_AUTO_CREATE
- | Context.BIND_FOREGROUND_SERVICE
- | Context.BIND_INCLUDE_CAPABILITIES,
+ getBindingFlags(isPrivileged),
userId,
IRecognitionService.Stub::asInterface);
@@ -85,6 +87,14 @@ final class RemoteSpeechRecognitionService extends ServiceConnector.Impl<IRecogn
}
}
+ private static int getBindingFlags(boolean isPrivileged) {
+ int bindingFlags = Context.BIND_AUTO_CREATE;
+ if (isPrivileged) {
+ bindingFlags |= Context.BIND_INCLUDE_CAPABILITIES | Context.BIND_FOREGROUND_SERVICE;
+ }
+ return bindingFlags;
+ }
+
ComponentName getServiceComponentName() {
return mComponentName;
}
diff --git a/services/core/java/com/android/server/speech/SpeechRecognitionManagerServiceImpl.java b/services/core/java/com/android/server/speech/SpeechRecognitionManagerServiceImpl.java
index 8e9c889c8ef3..808504f50acc 100644
--- a/services/core/java/com/android/server/speech/SpeechRecognitionManagerServiceImpl.java
+++ b/services/core/java/com/android/server/speech/SpeechRecognitionManagerServiceImpl.java
@@ -23,6 +23,7 @@ import android.app.AppGlobals;
import android.content.AttributionSource;
import android.content.ComponentName;
import android.content.Intent;
+import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.content.pm.ServiceInfo;
@@ -31,6 +32,7 @@ import android.os.IBinder;
import android.os.Process;
import android.os.RemoteException;
import android.permission.PermissionManager;
+import android.provider.Settings;
import android.speech.IModelDownloadListener;
import android.speech.IRecognitionListener;
import android.speech.IRecognitionService;
@@ -311,9 +313,22 @@ final class SpeechRecognitionManagerServiceImpl extends
return null;
}
+ final boolean isPrivileged;
+ if (serviceComponent == null) {
+ isPrivileged = false;
+ } else {
+ // Only certain privileged recognition service can obtain process capabilities
+ // from persistent process to hold while-in-use permission in the background.
+ isPrivileged = checkPrivilege(serviceComponent);
+ }
+
RemoteSpeechRecognitionService service =
new RemoteSpeechRecognitionService(
- getContext(), serviceComponent, getUserId(), callingUid);
+ getContext(),
+ serviceComponent,
+ getUserId(),
+ callingUid,
+ isPrivileged);
Set<RemoteSpeechRecognitionService> valuesByCaller =
mRemoteServicesByUid.computeIfAbsent(callingUid, key -> new HashSet<>());
@@ -328,6 +343,53 @@ final class SpeechRecognitionManagerServiceImpl extends
}
}
+ /**
+ * Checks if the given service component should have privileged binding flags when created. Only
+ * a service component that matches with any of the following condition would be granted:
+ *
+ * <ul>
+ * <li>A default recognition service component.</li>
+ * <li>An on-device recognition service component.</li>
+ * <li>A pre-installed recognition service component.</li>
+ * </ul>
+ */
+ @GuardedBy("mLock")
+ private boolean checkPrivilege(@NonNull ComponentName serviceComponent) {
+ final ComponentName defaultComponent = getDefaultRecognitionServiceComponent();
+ final ComponentName onDeviceComponent = getOnDeviceComponentNameLocked();
+ final boolean preinstalled = isPreinstalledApp(serviceComponent);
+ return serviceComponent.equals(defaultComponent)
+ || serviceComponent.equals(onDeviceComponent)
+ || preinstalled;
+ }
+
+ private boolean isPreinstalledApp(@NonNull ComponentName serviceComponent) {
+ PackageManager pm = getContext().getPackageManager();
+ if (pm == null) {
+ return false;
+ }
+
+ try {
+ ApplicationInfo info = pm.getApplicationInfoAsUser(serviceComponent.getPackageName(),
+ PackageManager.MATCH_SYSTEM_ONLY, getUserId());
+ return (info.flags & ApplicationInfo.FLAG_SYSTEM) != 0;
+ } catch (PackageManager.NameNotFoundException e) {
+ return false;
+ }
+ }
+
+ @Nullable
+ private ComponentName getDefaultRecognitionServiceComponent() {
+ String componentName = Settings.Secure.getStringForUser(
+ getContext().getContentResolver(),
+ Settings.Secure.VOICE_RECOGNITION_SERVICE,
+ getUserId());
+ if (componentName == null) {
+ return null;
+ }
+ return ComponentName.unflattenFromString(componentName);
+ }
+
private boolean componentMapsToRecognitionService(@NonNull ComponentName serviceComponent) {
List<ResolveInfo> resolveInfos;