Skip to content
Snippets Groups Projects
Commit 449490c4 authored by MingWei's avatar MingWei Committed by MingWei Liao
Browse files

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
parent 98a3f121
No related branches found
No related tags found
No related merge requests found
......@@ -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;
}
......
......@@ -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;
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment