Allow voice recognition service to blame other apps access.

This is a workaround solution for Android R QPR2. We are not allowed
to change the API for QPR release. This is a special case that allows
the current voice recognizer to note proxy ops if it is also the
voice interactor. In S, we will define a new permission that designed
one as a trusted blamer and tie it to a role.

Bug: 17095434
Test: manual
Test: TreeHugger presubmit
Change-Id: I506bbeb95e622b99693dbf5a135c7961b7fd81c1
This commit is contained in:
Joanne Chung
2020-10-29 20:29:18 +08:00
parent f21135e7e9
commit 38f832d4f3
2 changed files with 55 additions and 4 deletions

View File

@@ -31,6 +31,7 @@ import android.compat.Compatibility;
import android.compat.annotation.ChangeId;
import android.compat.annotation.EnabledAfter;
import android.compat.annotation.UnsupportedAppUsage;
import android.content.ComponentName;
import android.content.ContentResolver;
import android.content.Context;
import android.content.pm.PackageManager;
@@ -52,6 +53,7 @@ import android.os.RemoteException;
import android.os.ServiceManager;
import android.os.SystemClock;
import android.os.UserManager;
import android.provider.Settings;
import android.util.ArrayMap;
import android.util.ArraySet;
import android.util.LongSparseArray;
@@ -7590,8 +7592,9 @@ public class AppOpsManager {
collectNotedOpForSelf(op, proxiedAttributionTag);
} else if (collectionMode == COLLECT_SYNC
// Only collect app-ops when the proxy is trusted
&& mContext.checkPermission(Manifest.permission.UPDATE_APP_OPS_STATS, -1,
myUid) == PackageManager.PERMISSION_GRANTED) {
&& (mContext.checkPermission(Manifest.permission.UPDATE_APP_OPS_STATS, -1,
myUid) == PackageManager.PERMISSION_GRANTED
|| isTrustedVoiceServiceProxy(mContext.getOpPackageName(), op))) {
collectNotedOpSync(op, proxiedAttributionTag);
}
}
@@ -7602,6 +7605,28 @@ public class AppOpsManager {
}
}
private boolean isTrustedVoiceServiceProxy(String packageName, int code) {
// This is a workaround for R QPR, new API change is not allowed. We only allow the current
// voice recognizer is also the voice interactor to noteproxy op.
if (code != OP_RECORD_AUDIO) {
return false;
}
final String voiceRecognitionComponent = Settings.Secure.getString(
mContext.getContentResolver(), Settings.Secure.VOICE_RECOGNITION_SERVICE);
final String voiceInteractionComponent = Settings.Secure.getString(
mContext.getContentResolver(), Settings.Secure.VOICE_INTERACTION_SERVICE);
final String voiceRecognitionServicePackageName =
voiceRecognitionComponent != null ? ComponentName.unflattenFromString(
voiceRecognitionComponent).getPackageName() : "";
final String voiceInteractionServicePackageName =
voiceInteractionComponent != null ? ComponentName.unflattenFromString(
voiceInteractionComponent).getPackageName() : "";
return Objects.equals(packageName, voiceRecognitionServicePackageName) && Objects.equals(
voiceRecognitionServicePackageName, voiceInteractionServicePackageName);
}
/**
* Do a quick check for whether an application might be able to perform an operation.
* This is <em>not</em> a security check; you must use {@link #noteOp(String, int, String,

View File

@@ -94,6 +94,7 @@ import android.app.AsyncNotedAppOp;
import android.app.RuntimeAppOpAccessMessage;
import android.app.SyncNotedAppOp;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
@@ -3015,6 +3016,25 @@ public class AppOpsService extends IAppOpsService.Stub {
}
}
private boolean isTrustedVoiceServiceProxy(String packageName, int code) {
if (code != OP_RECORD_AUDIO) {
return false;
}
final String voiceRecognitionComponent = Settings.Secure.getString(
mContext.getContentResolver(), Settings.Secure.VOICE_RECOGNITION_SERVICE);
final String voiceInteractionComponent = Settings.Secure.getString(
mContext.getContentResolver(), Settings.Secure.VOICE_INTERACTION_SERVICE);
final String voiceRecognitionServicePackageName =
voiceRecognitionComponent != null ? ComponentName.unflattenFromString(
voiceRecognitionComponent).getPackageName() : "";
final String voiceInteractionServicePackageName =
voiceInteractionComponent != null ? ComponentName.unflattenFromString(
voiceInteractionComponent).getPackageName() : "";
return Objects.equals(packageName, voiceRecognitionServicePackageName) && Objects.equals(
voiceRecognitionServicePackageName, voiceInteractionServicePackageName);
}
@Override
public int noteProxyOperation(int code, int proxiedUid, String proxiedPackageName,
String proxiedAttributionTag, int proxyUid, String proxyPackageName,
@@ -3030,9 +3050,12 @@ public class AppOpsService extends IAppOpsService.Stub {
return AppOpsManager.MODE_IGNORED;
}
// This is a workaround for R QPR, new API change is not allowed. We only allow the current
// voice recognizer is also the voice interactor to noteproxy op.
final boolean isTrustVoiceServiceProxy = isTrustedVoiceServiceProxy(proxyPackageName, code);
final boolean isProxyTrusted = mContext.checkPermission(
Manifest.permission.UPDATE_APP_OPS_STATS, -1, proxyUid)
== PackageManager.PERMISSION_GRANTED;
== PackageManager.PERMISSION_GRANTED || isTrustVoiceServiceProxy;
final int proxyFlags = isProxyTrusted ? AppOpsManager.OP_FLAG_TRUSTED_PROXY
: AppOpsManager.OP_FLAG_UNTRUSTED_PROXY;
@@ -3494,9 +3517,12 @@ public class AppOpsService extends IAppOpsService.Stub {
return AppOpsManager.MODE_IGNORED;
}
// This is a workaround for R QPR, new API change is not allowed. We only allow the current
// voice recognizer is also the voice interactor to noteproxy op.
final boolean isTrustVoiceServiceProxy = isTrustedVoiceServiceProxy(proxyPackageName, code);
final boolean isProxyTrusted = mContext.checkPermission(
Manifest.permission.UPDATE_APP_OPS_STATS, -1, proxyUid)
== PackageManager.PERMISSION_GRANTED;
== PackageManager.PERMISSION_GRANTED || isTrustVoiceServiceProxy;
final int proxyFlags = isProxyTrusted ? AppOpsManager.OP_FLAG_TRUSTED_PROXY
: AppOpsManager.OP_FLAG_UNTRUSTED_PROXY;