Loading core/java/android/permission/PermissionManager.java +2 −4 Original line number Original line Diff line number Diff line Loading @@ -158,6 +158,8 @@ public final class PermissionManager { mPermissionManager = IPermissionManager.Stub.asInterface(ServiceManager.getServiceOrThrow( mPermissionManager = IPermissionManager.Stub.asInterface(ServiceManager.getServiceOrThrow( "permissionmgr")); "permissionmgr")); mLegacyPermissionManager = context.getSystemService(LegacyPermissionManager.class); mLegacyPermissionManager = context.getSystemService(LegacyPermissionManager.class); //TODO ntmyren: there should be a way to only enable the watcher when requested mUsageHelper = new PermissionUsageHelper(context); } } /** /** Loading Loading @@ -878,10 +880,6 @@ public final class PermissionManager { @NonNull @NonNull @RequiresPermission(Manifest.permission.GET_APP_OPS_STATS) @RequiresPermission(Manifest.permission.GET_APP_OPS_STATS) public List<PermGroupUsage> getIndicatorAppOpUsageData() { public List<PermGroupUsage> getIndicatorAppOpUsageData() { // Lazily initialize the usage helper if (mUsageHelper == null) { mUsageHelper = new PermissionUsageHelper(mContext); } return mUsageHelper.getOpUsageData(new AudioManager().isMicrophoneMute()); return mUsageHelper.getOpUsageData(new AudioManager().isMicrophoneMute()); } } Loading core/java/android/permission/PermissionUsageHelper.java +116 −4 Original line number Original line Diff line number Diff line Loading @@ -19,6 +19,10 @@ package android.permission; import static android.Manifest.permission_group.CAMERA; import static android.Manifest.permission_group.CAMERA; import static android.Manifest.permission_group.LOCATION; import static android.Manifest.permission_group.LOCATION; import static android.Manifest.permission_group.MICROPHONE; import static android.Manifest.permission_group.MICROPHONE; import static android.app.AppOpsManager.ATTRIBUTION_FLAGS_NONE; import static android.app.AppOpsManager.ATTRIBUTION_FLAG_ACCESSOR; import static android.app.AppOpsManager.ATTRIBUTION_FLAG_RECEIVER; import static android.app.AppOpsManager.AttributionFlags; import static android.app.AppOpsManager.OPSTR_CAMERA; import static android.app.AppOpsManager.OPSTR_CAMERA; import static android.app.AppOpsManager.OPSTR_COARSE_LOCATION; import static android.app.AppOpsManager.OPSTR_COARSE_LOCATION; import static android.app.AppOpsManager.OPSTR_FINE_LOCATION; import static android.app.AppOpsManager.OPSTR_FINE_LOCATION; Loading @@ -30,6 +34,7 @@ import static android.media.AudioSystem.MODE_IN_COMMUNICATION; import static android.telephony.TelephonyManager.CARRIER_PRIVILEGE_STATUS_HAS_ACCESS; import static android.telephony.TelephonyManager.CARRIER_PRIVILEGE_STATUS_HAS_ACCESS; import android.annotation.NonNull; import android.annotation.NonNull; import android.annotation.Nullable; import android.app.AppOpsManager; import android.app.AppOpsManager; import android.content.Context; import android.content.Context; import android.content.pm.ApplicationInfo; import android.content.pm.ApplicationInfo; Loading @@ -56,7 +61,7 @@ import java.util.Objects; * * * @hide * @hide */ */ public class PermissionUsageHelper { public class PermissionUsageHelper implements AppOpsManager.OnOpActiveChangedListener { /** Whether to show the mic and camera icons. */ /** Whether to show the mic and camera icons. */ private static final String PROPERTY_CAMERA_MIC_ICONS_ENABLED = "camera_mic_icons_enabled"; private static final String PROPERTY_CAMERA_MIC_ICONS_ENABLED = "camera_mic_icons_enabled"; Loading Loading @@ -140,6 +145,7 @@ public class PermissionUsageHelper { private ArrayMap<UserHandle, Context> mUserContexts; private ArrayMap<UserHandle, Context> mUserContexts; private PackageManager mPkgManager; private PackageManager mPkgManager; private AppOpsManager mAppOpsManager; private AppOpsManager mAppOpsManager; private ArrayMap<Integer, ArrayList<AccessChainLink>> mAttributionChains = new ArrayMap<>(); /** /** * Constructor for PermissionUsageHelper * Constructor for PermissionUsageHelper Loading @@ -151,6 +157,10 @@ public class PermissionUsageHelper { mAppOpsManager = context.getSystemService(AppOpsManager.class); mAppOpsManager = context.getSystemService(AppOpsManager.class); mUserContexts = new ArrayMap<>(); mUserContexts = new ArrayMap<>(); mUserContexts.put(Process.myUserHandle(), mContext); mUserContexts.put(Process.myUserHandle(), mContext); // TODO ntmyren: make this listen for flag enable/disable changes String[] ops = { OPSTR_CAMERA, OPSTR_RECORD_AUDIO }; mContext.getSystemService(AppOpsManager.class).startWatchingActive(ops, context.getMainExecutor(), this); } } private Context getUserContext(UserHandle user) { private Context getUserContext(UserHandle user) { Loading @@ -160,6 +170,45 @@ public class PermissionUsageHelper { return mUserContexts.get(user); return mUserContexts.get(user); } } @Override public void onOpActiveChanged(@NonNull String op, int uid, @NonNull String packageName, boolean active) { // not part of an attribution chain. Do nothing } @Override public void onOpActiveChanged(@NonNull String op, int uid, @NonNull String packageName, @Nullable String attributionTag, boolean active, @AttributionFlags int attributionFlags, int attributionChainId) { if ((attributionFlags & ATTRIBUTION_FLAGS_NONE) != 0) { return; } if (!active) { // if any link in the chain is finished, remove the chain. // TODO ntmyren: be smarter about this mAttributionChains.remove(attributionChainId); return; } ArrayList<AccessChainLink> currentChain = mAttributionChains.computeIfAbsent( attributionChainId, k -> new ArrayList<>()); AccessChainLink link = new AccessChainLink(op, packageName, attributionTag, uid, attributionFlags); int currSize = currentChain.size(); if (currSize == 0 || link.isEnd() || !currentChain.get(currSize - 1).isEnd()) { // if the list is empty, this link is the end, or the last link in the current chain // isn't the end, add it to the end currentChain.add(link); } else if (link.isStart()) { currentChain.add(0, link); } else if (currentChain.get(currentChain.size() - 1).isEnd()) { // we already have the end, and this is a mid node, so insert before the end currentChain.add(currSize - 1, link); } } /** /** * @see PermissionManager.getIndicatorAppOpUsageData * @see PermissionManager.getIndicatorAppOpUsageData */ */ Loading Loading @@ -331,7 +380,7 @@ public class PermissionUsageHelper { private ArrayMap<OpUsage, CharSequence> getUniqueUsagesWithLabels(List<OpUsage> usages) { private ArrayMap<OpUsage, CharSequence> getUniqueUsagesWithLabels(List<OpUsage> usages) { ArrayMap<OpUsage, CharSequence> usagesAndLabels = new ArrayMap<>(); ArrayMap<OpUsage, CharSequence> usagesAndLabels = new ArrayMap<>(); if (usages == null) { if (usages == null || usages.isEmpty()) { return usagesAndLabels; return usagesAndLabels; } } Loading Loading @@ -430,9 +479,52 @@ public class PermissionUsageHelper { } } iterNum++; iterNum++; } } // TODO ntmyren: remove this proxy logic once camera is converted to AttributionSource // For now: don't add mic proxy usages if (!start.op.equals(OPSTR_RECORD_AUDIO)) { usagesAndLabels.put(start, usagesAndLabels.put(start, proxyLabelList.isEmpty() ? null : formatLabelList(proxyLabelList)); proxyLabelList.isEmpty() ? null : formatLabelList(proxyLabelList)); } } } for (int i = 0; i < mAttributionChains.size(); i++) { List<AccessChainLink> usageList = mAttributionChains.valueAt(i); int lastVisible = usageList.size() - 1; // TODO ntmyren: remove this mic code once camera is converted to AttributionSource // if the list is empty or incomplete, do not show it. if (usageList.isEmpty() || !usageList.get(lastVisible).isEnd() || !usageList.get(0).isStart() || !usageList.get(lastVisible).usage.op.equals(OPSTR_RECORD_AUDIO)) { continue; } //TODO ntmyren: remove once camera etc. etc. for (AccessChainLink link: usageList) { proxyPackages.add(link.usage.getPackageIdHash()); } AccessChainLink start = usageList.get(0); AccessChainLink lastVisibleLink = usageList.get(lastVisible); while (lastVisible > 0 && !shouldShowPackage(lastVisibleLink.usage.packageName)) { lastVisible--; lastVisibleLink = usageList.get(lastVisible); } String proxyLabel = null; if (!lastVisibleLink.usage.packageName.equals(start.usage.packageName)) { try { PackageManager userPkgManager = getUserContext(lastVisibleLink.usage.getUser()).getPackageManager(); ApplicationInfo appInfo = userPkgManager.getApplicationInfo( lastVisibleLink.usage.packageName, 0); proxyLabel = appInfo.loadLabel(userPkgManager).toString(); } catch (PackageManager.NameNotFoundException e) { // do nothing } } usagesAndLabels.put(start.usage, proxyLabel); } for (int packageHash : mostRecentUsages.keySet()) { for (int packageHash : mostRecentUsages.keySet()) { if (!proxyPackages.contains(packageHash)) { if (!proxyPackages.contains(packageHash)) { Loading Loading @@ -495,4 +587,24 @@ public class PermissionUsageHelper { && lastAccessTime == other.lastAccessTime && isRunning == other.isRunning; && lastAccessTime == other.lastAccessTime && isRunning == other.isRunning; } } } } private static class AccessChainLink { public final OpUsage usage; public final @AttributionFlags int flags; AccessChainLink(String op, String packageName, String attributionTag, int uid, int flags) { this.usage = new OpUsage(packageName, attributionTag, op, uid, System.currentTimeMillis(), true, null); this.flags = flags; } public boolean isEnd() { return (flags & ATTRIBUTION_FLAG_ACCESSOR) != 0; } public boolean isStart() { return (flags & ATTRIBUTION_FLAG_RECEIVER) != 0; } } } } services/core/java/com/android/server/appop/AppOpsService.java +2 −10 Original line number Original line Diff line number Diff line Loading @@ -84,8 +84,8 @@ import android.app.ActivityManager; import android.app.ActivityManagerInternal; import android.app.ActivityManagerInternal; import android.app.AppGlobals; import android.app.AppGlobals; import android.app.AppOpsManager; import android.app.AppOpsManager; import android.app.AppOpsManager.AttributionFlags; import android.app.AppOpsManager.AttributedOpEntry; import android.app.AppOpsManager.AttributedOpEntry; import android.app.AppOpsManager.AttributionFlags; import android.app.AppOpsManager.HistoricalOps; import android.app.AppOpsManager.HistoricalOps; import android.app.AppOpsManager.Mode; import android.app.AppOpsManager.Mode; import android.app.AppOpsManager.OpEntry; import android.app.AppOpsManager.OpEntry; Loading Loading @@ -3255,13 +3255,6 @@ public class AppOpsService extends IAppOpsService.Stub { shouldCollectAsyncNotedOp, message, shouldCollectMessage, skipProxyOperation); shouldCollectAsyncNotedOp, message, shouldCollectMessage, skipProxyOperation); } } // TODO b/184963112: remove once full blaming is implemented private boolean isRecognitionServiceTemp(int code, String packageName) { return code == OP_RECORD_AUDIO && (packageName.equals("com.google.android.googlequicksearchbox") || packageName.equals("com.google.android.tts")); } private SyncNotedAppOp noteProxyOperationImpl(int code, AttributionSource attributionSource, private SyncNotedAppOp noteProxyOperationImpl(int code, AttributionSource attributionSource, boolean shouldCollectAsyncNotedOp, String message, boolean shouldCollectMessage, boolean shouldCollectAsyncNotedOp, String message, boolean shouldCollectMessage, boolean skipProxyOperation) { boolean skipProxyOperation) { Loading Loading @@ -3289,8 +3282,7 @@ public class AppOpsService extends IAppOpsService.Stub { final boolean isSelfBlame = Binder.getCallingUid() == proxiedUid; final boolean isSelfBlame = Binder.getCallingUid() == proxiedUid; final boolean isProxyTrusted = mContext.checkPermission( final boolean isProxyTrusted = mContext.checkPermission( Manifest.permission.UPDATE_APP_OPS_STATS, -1, proxyUid) Manifest.permission.UPDATE_APP_OPS_STATS, -1, proxyUid) == PackageManager.PERMISSION_GRANTED || isSelfBlame == PackageManager.PERMISSION_GRANTED || isSelfBlame; || isRecognitionServiceTemp(code, proxyPackageName); if (!skipProxyOperation) { if (!skipProxyOperation) { final int proxyFlags = isProxyTrusted ? AppOpsManager.OP_FLAG_TRUSTED_PROXY final int proxyFlags = isProxyTrusted ? AppOpsManager.OP_FLAG_TRUSTED_PROXY Loading Loading
core/java/android/permission/PermissionManager.java +2 −4 Original line number Original line Diff line number Diff line Loading @@ -158,6 +158,8 @@ public final class PermissionManager { mPermissionManager = IPermissionManager.Stub.asInterface(ServiceManager.getServiceOrThrow( mPermissionManager = IPermissionManager.Stub.asInterface(ServiceManager.getServiceOrThrow( "permissionmgr")); "permissionmgr")); mLegacyPermissionManager = context.getSystemService(LegacyPermissionManager.class); mLegacyPermissionManager = context.getSystemService(LegacyPermissionManager.class); //TODO ntmyren: there should be a way to only enable the watcher when requested mUsageHelper = new PermissionUsageHelper(context); } } /** /** Loading Loading @@ -878,10 +880,6 @@ public final class PermissionManager { @NonNull @NonNull @RequiresPermission(Manifest.permission.GET_APP_OPS_STATS) @RequiresPermission(Manifest.permission.GET_APP_OPS_STATS) public List<PermGroupUsage> getIndicatorAppOpUsageData() { public List<PermGroupUsage> getIndicatorAppOpUsageData() { // Lazily initialize the usage helper if (mUsageHelper == null) { mUsageHelper = new PermissionUsageHelper(mContext); } return mUsageHelper.getOpUsageData(new AudioManager().isMicrophoneMute()); return mUsageHelper.getOpUsageData(new AudioManager().isMicrophoneMute()); } } Loading
core/java/android/permission/PermissionUsageHelper.java +116 −4 Original line number Original line Diff line number Diff line Loading @@ -19,6 +19,10 @@ package android.permission; import static android.Manifest.permission_group.CAMERA; import static android.Manifest.permission_group.CAMERA; import static android.Manifest.permission_group.LOCATION; import static android.Manifest.permission_group.LOCATION; import static android.Manifest.permission_group.MICROPHONE; import static android.Manifest.permission_group.MICROPHONE; import static android.app.AppOpsManager.ATTRIBUTION_FLAGS_NONE; import static android.app.AppOpsManager.ATTRIBUTION_FLAG_ACCESSOR; import static android.app.AppOpsManager.ATTRIBUTION_FLAG_RECEIVER; import static android.app.AppOpsManager.AttributionFlags; import static android.app.AppOpsManager.OPSTR_CAMERA; import static android.app.AppOpsManager.OPSTR_CAMERA; import static android.app.AppOpsManager.OPSTR_COARSE_LOCATION; import static android.app.AppOpsManager.OPSTR_COARSE_LOCATION; import static android.app.AppOpsManager.OPSTR_FINE_LOCATION; import static android.app.AppOpsManager.OPSTR_FINE_LOCATION; Loading @@ -30,6 +34,7 @@ import static android.media.AudioSystem.MODE_IN_COMMUNICATION; import static android.telephony.TelephonyManager.CARRIER_PRIVILEGE_STATUS_HAS_ACCESS; import static android.telephony.TelephonyManager.CARRIER_PRIVILEGE_STATUS_HAS_ACCESS; import android.annotation.NonNull; import android.annotation.NonNull; import android.annotation.Nullable; import android.app.AppOpsManager; import android.app.AppOpsManager; import android.content.Context; import android.content.Context; import android.content.pm.ApplicationInfo; import android.content.pm.ApplicationInfo; Loading @@ -56,7 +61,7 @@ import java.util.Objects; * * * @hide * @hide */ */ public class PermissionUsageHelper { public class PermissionUsageHelper implements AppOpsManager.OnOpActiveChangedListener { /** Whether to show the mic and camera icons. */ /** Whether to show the mic and camera icons. */ private static final String PROPERTY_CAMERA_MIC_ICONS_ENABLED = "camera_mic_icons_enabled"; private static final String PROPERTY_CAMERA_MIC_ICONS_ENABLED = "camera_mic_icons_enabled"; Loading Loading @@ -140,6 +145,7 @@ public class PermissionUsageHelper { private ArrayMap<UserHandle, Context> mUserContexts; private ArrayMap<UserHandle, Context> mUserContexts; private PackageManager mPkgManager; private PackageManager mPkgManager; private AppOpsManager mAppOpsManager; private AppOpsManager mAppOpsManager; private ArrayMap<Integer, ArrayList<AccessChainLink>> mAttributionChains = new ArrayMap<>(); /** /** * Constructor for PermissionUsageHelper * Constructor for PermissionUsageHelper Loading @@ -151,6 +157,10 @@ public class PermissionUsageHelper { mAppOpsManager = context.getSystemService(AppOpsManager.class); mAppOpsManager = context.getSystemService(AppOpsManager.class); mUserContexts = new ArrayMap<>(); mUserContexts = new ArrayMap<>(); mUserContexts.put(Process.myUserHandle(), mContext); mUserContexts.put(Process.myUserHandle(), mContext); // TODO ntmyren: make this listen for flag enable/disable changes String[] ops = { OPSTR_CAMERA, OPSTR_RECORD_AUDIO }; mContext.getSystemService(AppOpsManager.class).startWatchingActive(ops, context.getMainExecutor(), this); } } private Context getUserContext(UserHandle user) { private Context getUserContext(UserHandle user) { Loading @@ -160,6 +170,45 @@ public class PermissionUsageHelper { return mUserContexts.get(user); return mUserContexts.get(user); } } @Override public void onOpActiveChanged(@NonNull String op, int uid, @NonNull String packageName, boolean active) { // not part of an attribution chain. Do nothing } @Override public void onOpActiveChanged(@NonNull String op, int uid, @NonNull String packageName, @Nullable String attributionTag, boolean active, @AttributionFlags int attributionFlags, int attributionChainId) { if ((attributionFlags & ATTRIBUTION_FLAGS_NONE) != 0) { return; } if (!active) { // if any link in the chain is finished, remove the chain. // TODO ntmyren: be smarter about this mAttributionChains.remove(attributionChainId); return; } ArrayList<AccessChainLink> currentChain = mAttributionChains.computeIfAbsent( attributionChainId, k -> new ArrayList<>()); AccessChainLink link = new AccessChainLink(op, packageName, attributionTag, uid, attributionFlags); int currSize = currentChain.size(); if (currSize == 0 || link.isEnd() || !currentChain.get(currSize - 1).isEnd()) { // if the list is empty, this link is the end, or the last link in the current chain // isn't the end, add it to the end currentChain.add(link); } else if (link.isStart()) { currentChain.add(0, link); } else if (currentChain.get(currentChain.size() - 1).isEnd()) { // we already have the end, and this is a mid node, so insert before the end currentChain.add(currSize - 1, link); } } /** /** * @see PermissionManager.getIndicatorAppOpUsageData * @see PermissionManager.getIndicatorAppOpUsageData */ */ Loading Loading @@ -331,7 +380,7 @@ public class PermissionUsageHelper { private ArrayMap<OpUsage, CharSequence> getUniqueUsagesWithLabels(List<OpUsage> usages) { private ArrayMap<OpUsage, CharSequence> getUniqueUsagesWithLabels(List<OpUsage> usages) { ArrayMap<OpUsage, CharSequence> usagesAndLabels = new ArrayMap<>(); ArrayMap<OpUsage, CharSequence> usagesAndLabels = new ArrayMap<>(); if (usages == null) { if (usages == null || usages.isEmpty()) { return usagesAndLabels; return usagesAndLabels; } } Loading Loading @@ -430,9 +479,52 @@ public class PermissionUsageHelper { } } iterNum++; iterNum++; } } // TODO ntmyren: remove this proxy logic once camera is converted to AttributionSource // For now: don't add mic proxy usages if (!start.op.equals(OPSTR_RECORD_AUDIO)) { usagesAndLabels.put(start, usagesAndLabels.put(start, proxyLabelList.isEmpty() ? null : formatLabelList(proxyLabelList)); proxyLabelList.isEmpty() ? null : formatLabelList(proxyLabelList)); } } } for (int i = 0; i < mAttributionChains.size(); i++) { List<AccessChainLink> usageList = mAttributionChains.valueAt(i); int lastVisible = usageList.size() - 1; // TODO ntmyren: remove this mic code once camera is converted to AttributionSource // if the list is empty or incomplete, do not show it. if (usageList.isEmpty() || !usageList.get(lastVisible).isEnd() || !usageList.get(0).isStart() || !usageList.get(lastVisible).usage.op.equals(OPSTR_RECORD_AUDIO)) { continue; } //TODO ntmyren: remove once camera etc. etc. for (AccessChainLink link: usageList) { proxyPackages.add(link.usage.getPackageIdHash()); } AccessChainLink start = usageList.get(0); AccessChainLink lastVisibleLink = usageList.get(lastVisible); while (lastVisible > 0 && !shouldShowPackage(lastVisibleLink.usage.packageName)) { lastVisible--; lastVisibleLink = usageList.get(lastVisible); } String proxyLabel = null; if (!lastVisibleLink.usage.packageName.equals(start.usage.packageName)) { try { PackageManager userPkgManager = getUserContext(lastVisibleLink.usage.getUser()).getPackageManager(); ApplicationInfo appInfo = userPkgManager.getApplicationInfo( lastVisibleLink.usage.packageName, 0); proxyLabel = appInfo.loadLabel(userPkgManager).toString(); } catch (PackageManager.NameNotFoundException e) { // do nothing } } usagesAndLabels.put(start.usage, proxyLabel); } for (int packageHash : mostRecentUsages.keySet()) { for (int packageHash : mostRecentUsages.keySet()) { if (!proxyPackages.contains(packageHash)) { if (!proxyPackages.contains(packageHash)) { Loading Loading @@ -495,4 +587,24 @@ public class PermissionUsageHelper { && lastAccessTime == other.lastAccessTime && isRunning == other.isRunning; && lastAccessTime == other.lastAccessTime && isRunning == other.isRunning; } } } } private static class AccessChainLink { public final OpUsage usage; public final @AttributionFlags int flags; AccessChainLink(String op, String packageName, String attributionTag, int uid, int flags) { this.usage = new OpUsage(packageName, attributionTag, op, uid, System.currentTimeMillis(), true, null); this.flags = flags; } public boolean isEnd() { return (flags & ATTRIBUTION_FLAG_ACCESSOR) != 0; } public boolean isStart() { return (flags & ATTRIBUTION_FLAG_RECEIVER) != 0; } } } }
services/core/java/com/android/server/appop/AppOpsService.java +2 −10 Original line number Original line Diff line number Diff line Loading @@ -84,8 +84,8 @@ import android.app.ActivityManager; import android.app.ActivityManagerInternal; import android.app.ActivityManagerInternal; import android.app.AppGlobals; import android.app.AppGlobals; import android.app.AppOpsManager; import android.app.AppOpsManager; import android.app.AppOpsManager.AttributionFlags; import android.app.AppOpsManager.AttributedOpEntry; import android.app.AppOpsManager.AttributedOpEntry; import android.app.AppOpsManager.AttributionFlags; import android.app.AppOpsManager.HistoricalOps; import android.app.AppOpsManager.HistoricalOps; import android.app.AppOpsManager.Mode; import android.app.AppOpsManager.Mode; import android.app.AppOpsManager.OpEntry; import android.app.AppOpsManager.OpEntry; Loading Loading @@ -3255,13 +3255,6 @@ public class AppOpsService extends IAppOpsService.Stub { shouldCollectAsyncNotedOp, message, shouldCollectMessage, skipProxyOperation); shouldCollectAsyncNotedOp, message, shouldCollectMessage, skipProxyOperation); } } // TODO b/184963112: remove once full blaming is implemented private boolean isRecognitionServiceTemp(int code, String packageName) { return code == OP_RECORD_AUDIO && (packageName.equals("com.google.android.googlequicksearchbox") || packageName.equals("com.google.android.tts")); } private SyncNotedAppOp noteProxyOperationImpl(int code, AttributionSource attributionSource, private SyncNotedAppOp noteProxyOperationImpl(int code, AttributionSource attributionSource, boolean shouldCollectAsyncNotedOp, String message, boolean shouldCollectMessage, boolean shouldCollectAsyncNotedOp, String message, boolean shouldCollectMessage, boolean skipProxyOperation) { boolean skipProxyOperation) { Loading Loading @@ -3289,8 +3282,7 @@ public class AppOpsService extends IAppOpsService.Stub { final boolean isSelfBlame = Binder.getCallingUid() == proxiedUid; final boolean isSelfBlame = Binder.getCallingUid() == proxiedUid; final boolean isProxyTrusted = mContext.checkPermission( final boolean isProxyTrusted = mContext.checkPermission( Manifest.permission.UPDATE_APP_OPS_STATS, -1, proxyUid) Manifest.permission.UPDATE_APP_OPS_STATS, -1, proxyUid) == PackageManager.PERMISSION_GRANTED || isSelfBlame == PackageManager.PERMISSION_GRANTED || isSelfBlame; || isRecognitionServiceTemp(code, proxyPackageName); if (!skipProxyOperation) { if (!skipProxyOperation) { final int proxyFlags = isProxyTrusted ? AppOpsManager.OP_FLAG_TRUSTED_PROXY final int proxyFlags = isProxyTrusted ? AppOpsManager.OP_FLAG_TRUSTED_PROXY Loading