Loading core/java/android/app/AppOpsManager.java +160 −103 Original line number Diff line number Diff line Loading @@ -2849,14 +2849,14 @@ public class AppOpsManager { private static final ThreadLocal<Integer> sBinderThreadCallingUid = new ThreadLocal<>(); /** * If a thread is currently executing a two-way binder transaction, this stores the * ops that were noted blaming any app (the caller, the caller of the caller, etc). * If a thread is currently executing a two-way binder transaction, this stores the op-codes of * the app-ops that were noted during this transaction. * * @see #getNotedOpCollectionMode * @see #collectNotedOpSync */ private static final ThreadLocal<ArrayMap<String, ArrayMap<String, long[]>>> sAppOpsNotedInThisBinderTransaction = new ThreadLocal<>(); private static final ThreadLocal<ArrayMap<String, long[]>> sAppOpsNotedInThisBinderTransaction = new ThreadLocal<>(); /** Whether noting for an appop should be collected */ private static final @ShouldCollectNoteOp byte[] sAppOpsToNote = new byte[_NUM_OP]; Loading Loading @@ -7205,6 +7205,34 @@ public class AppOpsManager { * @hide */ public interface OnOpStartedListener { /** * Represents a start operation that was unsuccessful * @hide */ public int START_TYPE_FAILED = 0; /** * Represents a successful start operation * @hide */ public int START_TYPE_STARTED = 1; /** * Represents an operation where a restricted operation became unrestricted, and resumed. * @hide */ public int START_TYPE_RESUMED = 2; /** @hide */ @Retention(RetentionPolicy.SOURCE) @IntDef(flag = true, prefix = { "TYPE_" }, value = { START_TYPE_FAILED, START_TYPE_STARTED, START_TYPE_RESUMED }) public @interface StartedType {} /** * Called when an op was started. * Loading @@ -7213,11 +7241,35 @@ public class AppOpsManager { * @param uid The UID performing the operation. * @param packageName The package performing the operation. * @param attributionTag The attribution tag performing the operation. * @param flags The flags of this op * @param flags The flags of this op. * @param result The result of the start. */ void onOpStarted(int op, int uid, String packageName, String attributionTag, @OpFlags int flags, @Mode int result); /** * Called when an op was started. * * Note: This is only for op starts. It is not called when an op is noted or stopped. * By default, unless this method is overridden, no code will be executed for resume * events. * @param op The op code. * @param uid The UID performing the operation. * @param packageName The package performing the operation. * @param attributionTag The attribution tag performing the operation. * @param flags The flags of this op. * @param result The result of the start. * @param startType The start type of this start event. Either failed, resumed, or started. * @param attributionFlags The location of this started op in an attribution chain. * @param attributionChainId The ID of the attribution chain of this op, if it is in one. */ default void onOpStarted(int op, int uid, String packageName, String attributionTag, @OpFlags int flags, @Mode int result, @StartedType int startType, @AttributionFlags int attributionFlags, int attributionChainId) { if (startType != START_TYPE_RESUMED) { onOpStarted(op, uid, packageName, attributionTag, flags, result); } } } AppOpsManager(Context context, IAppOpsService service) { Loading Loading @@ -7858,8 +7910,10 @@ public class AppOpsManager { cb = new IAppOpsStartedCallback.Stub() { @Override public void opStarted(int op, int uid, String packageName, String attributionTag, int flags, int mode) { callback.onOpStarted(op, uid, packageName, attributionTag, flags, mode); int flags, int mode, int startType, int attributionFlags, int attributionChainId) { callback.onOpStarted(op, uid, packageName, attributionTag, flags, mode, startType, attributionFlags, attributionChainId); } }; mStartedWatchers.put(callback, cb); Loading Loading @@ -9051,6 +9105,66 @@ public class AppOpsManager { sBinderThreadCallingUid.set(callingUid); } /** * State of a temporarily paused noted app-ops collection. * * @see #pauseNotedAppOpsCollection() * * @hide */ public static class PausedNotedAppOpsCollection { final int mUid; final @Nullable ArrayMap<String, long[]> mCollectedNotedAppOps; PausedNotedAppOpsCollection(int uid, @Nullable ArrayMap<String, long[]> collectedNotedAppOps) { mUid = uid; mCollectedNotedAppOps = collectedNotedAppOps; } } /** * Temporarily suspend collection of noted app-ops when binder-thread calls into the other * process. During such a call there might be call-backs coming back on the same thread which * should not be accounted to the current collection. * * @return a state needed to resume the collection * * @hide */ public static @Nullable PausedNotedAppOpsCollection pauseNotedAppOpsCollection() { Integer previousUid = sBinderThreadCallingUid.get(); if (previousUid != null) { ArrayMap<String, long[]> previousCollectedNotedAppOps = sAppOpsNotedInThisBinderTransaction.get(); sBinderThreadCallingUid.remove(); sAppOpsNotedInThisBinderTransaction.remove(); return new PausedNotedAppOpsCollection(previousUid, previousCollectedNotedAppOps); } return null; } /** * Resume a collection paused via {@link #pauseNotedAppOpsCollection}. * * @param prevCollection The state of the previous collection * * @hide */ public static void resumeNotedAppOpsCollection( @Nullable PausedNotedAppOpsCollection prevCollection) { if (prevCollection != null) { sBinderThreadCallingUid.set(prevCollection.mUid); if (prevCollection.mCollectedNotedAppOps != null) { sAppOpsNotedInThisBinderTransaction.set(prevCollection.mCollectedNotedAppOps); } } } /** * Finish collection of noted appops on this thread. * Loading Loading @@ -9091,47 +9205,26 @@ public class AppOpsManager { */ @TestApi public static void collectNotedOpSync(@NonNull SyncNotedAppOp syncOp) { collectNotedOpSync(sOpStrToOp.get(syncOp.getOp()), syncOp.getAttributionTag(), syncOp.getPackageName()); } /** * Collect a noted op when inside of a two-way binder call. * * <p> Delivered to caller via {@link #prefixParcelWithAppOpsIfNeeded} * * @param code the op code to note for * @param attributionTag the attribution tag to note for * @param packageName the package to note for */ private static void collectNotedOpSync(int code, @Nullable String attributionTag, @NonNull String packageName) { // If this is inside of a two-way binder call: // We are inside of a two-way binder call. Delivered to caller via // {@link #prefixParcelWithAppOpsIfNeeded} ArrayMap<String, ArrayMap<String, long[]>> appOpsNoted = sAppOpsNotedInThisBinderTransaction.get(); int op = sOpStrToOp.get(syncOp.getOp()); ArrayMap<String, long[]> appOpsNoted = sAppOpsNotedInThisBinderTransaction.get(); if (appOpsNoted == null) { appOpsNoted = new ArrayMap<>(1); sAppOpsNotedInThisBinderTransaction.set(appOpsNoted); } ArrayMap<String, long[]> packageAppOpsNotedForAttribution = appOpsNoted.get(packageName); if (packageAppOpsNotedForAttribution == null) { packageAppOpsNotedForAttribution = new ArrayMap<>(1); appOpsNoted.put(packageName, packageAppOpsNotedForAttribution); } long[] appOpsNotedForAttribution = packageAppOpsNotedForAttribution.get(attributionTag); long[] appOpsNotedForAttribution = appOpsNoted.get(syncOp.getAttributionTag()); if (appOpsNotedForAttribution == null) { appOpsNotedForAttribution = new long[2]; packageAppOpsNotedForAttribution.put(attributionTag, appOpsNotedForAttribution); appOpsNoted.put(syncOp.getAttributionTag(), appOpsNotedForAttribution); } if (code < 64) { appOpsNotedForAttribution[0] |= 1L << code; if (op < 64) { appOpsNotedForAttribution[0] |= 1L << op; } else { appOpsNotedForAttribution[1] |= 1L << (code - 64); appOpsNotedForAttribution[1] |= 1L << (op - 64); } } Loading Loading @@ -9185,7 +9278,9 @@ public class AppOpsManager { } } if (isListeningForOpNotedInBinderTransaction()) { Integer binderUid = sBinderThreadCallingUid.get(); if (binderUid != null && binderUid == uid) { return COLLECT_SYNC; } else { return COLLECT_ASYNC; Loading @@ -9204,32 +9299,20 @@ public class AppOpsManager { */ // TODO (b/186872903) Refactor how sync noted ops are propagated. public static void prefixParcelWithAppOpsIfNeeded(@NonNull Parcel p) { if (!isListeningForOpNotedInBinderTransaction()) { return; } final ArrayMap<String, ArrayMap<String, long[]>> notedAppOps = sAppOpsNotedInThisBinderTransaction.get(); ArrayMap<String, long[]> notedAppOps = sAppOpsNotedInThisBinderTransaction.get(); if (notedAppOps == null) { return; } p.writeInt(Parcel.EX_HAS_NOTED_APPOPS_REPLY_HEADER); final int packageCount = notedAppOps.size(); p.writeInt(packageCount); int numAttributionWithNotesAppOps = notedAppOps.size(); p.writeInt(numAttributionWithNotesAppOps); for (int i = 0; i < packageCount; i++) { for (int i = 0; i < numAttributionWithNotesAppOps; i++) { p.writeString(notedAppOps.keyAt(i)); final ArrayMap<String, long[]> notedTagAppOps = notedAppOps.valueAt(i); final int tagCount = notedTagAppOps.size(); p.writeInt(tagCount); for (int j = 0; j < tagCount; j++) { p.writeString(notedTagAppOps.keyAt(j)); p.writeLong(notedTagAppOps.valueAt(j)[0]); p.writeLong(notedTagAppOps.valueAt(j)[1]); } p.writeLong(notedAppOps.valueAt(i)[0]); p.writeLong(notedAppOps.valueAt(i)[1]); } } Loading @@ -9244,54 +9327,36 @@ public class AppOpsManager { * @hide */ public static void readAndLogNotedAppops(@NonNull Parcel p) { final int packageCount = p.readInt(); if (packageCount <= 0) { return; } int numAttributionsWithNotedAppOps = p.readInt(); final String myPackageName = ActivityThread.currentPackageName(); synchronized (sLock) { for (int i = 0; i < packageCount; i++) { final String packageName = p.readString(); final int tagCount = p.readInt(); for (int j = 0; j < tagCount; j++) { final String attributionTag = p.readString(); final long[] rawNotedAppOps = new long[2]; for (int i = 0; i < numAttributionsWithNotedAppOps; i++) { String attributionTag = p.readString(); long[] rawNotedAppOps = new long[2]; rawNotedAppOps[0] = p.readLong(); rawNotedAppOps[1] = p.readLong(); if (rawNotedAppOps[0] == 0 && rawNotedAppOps[1] == 0) { continue; } if (rawNotedAppOps[0] != 0 || rawNotedAppOps[1] != 0) { BitSet notedAppOps = BitSet.valueOf(rawNotedAppOps); final BitSet notedAppOps = BitSet.valueOf(rawNotedAppOps); synchronized (sLock) { for (int code = notedAppOps.nextSetBit(0); code != -1; code = notedAppOps.nextSetBit(code + 1)) { if (Objects.equals(myPackageName, packageName)) { if (sOnOpNotedCallback != null) { sOnOpNotedCallback.onNoted(new SyncNotedAppOp(code, attributionTag, packageName)); sOnOpNotedCallback.onNoted(new SyncNotedAppOp(code, attributionTag)); } else { String message = getFormattedStackTrace(); sUnforwardedOps.add(new AsyncNotedAppOp(code, Process.myUid(), attributionTag, message, System.currentTimeMillis())); sUnforwardedOps.add( new AsyncNotedAppOp(code, Process.myUid(), attributionTag, message, System.currentTimeMillis())); if (sUnforwardedOps.size() > MAX_UNFORWARDED_OPS) { sUnforwardedOps.remove(0); } } } else if (isListeningForOpNotedInBinderTransaction()) { collectNotedOpSync(code, attributionTag, packageName); } } for (int code = notedAppOps.nextSetBit(0); code != -1; code = notedAppOps.nextSetBit(code + 1)) { if (Objects.equals(myPackageName, packageName)) { sMessageCollector.onNoted(new SyncNotedAppOp(code, attributionTag, packageName)); } } sMessageCollector.onNoted(new SyncNotedAppOp(code, attributionTag)); } } } Loading Loading @@ -9398,15 +9463,7 @@ public class AppOpsManager { * @hide */ public static boolean isListeningForOpNoted() { return sOnOpNotedCallback != null || isListeningForOpNotedInBinderTransaction() || isCollectingStackTraces(); } /** * @return whether we are in a binder transaction and collecting appops. */ private static boolean isListeningForOpNotedInBinderTransaction() { return sBinderThreadCallingUid.get() != null; return sOnOpNotedCallback != null || isCollectingStackTraces(); } /** Loading core/java/android/app/SyncNotedAppOp.java +2 −1 Original line number Diff line number Diff line Loading @@ -21,7 +21,6 @@ import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.TestApi; import android.os.Parcelable; import android.os.Process; import com.android.internal.annotations.Immutable; import com.android.internal.util.DataClass; Loading @@ -29,6 +28,8 @@ import com.android.internal.util.DataClass; /** * Description of an app-op that was noted for the current process. * * Note: package name is currently unused in the system. * * <p>This is either delivered after a * {@link AppOpsManager.OnOpNotedCallback#onNoted(SyncNotedAppOp) two way binder call} or * when the app Loading core/java/android/os/BinderProxy.java +5 −0 Original line number Diff line number Diff line Loading @@ -560,6 +560,9 @@ public final class BinderProxy implements IBinder { } } final AppOpsManager.PausedNotedAppOpsCollection prevCollection = AppOpsManager.pauseNotedAppOpsCollection(); if ((flags & FLAG_ONEWAY) == 0 && AppOpsManager.isListeningForOpNoted()) { flags |= FLAG_COLLECT_NOTED_APP_OPS; } Loading @@ -567,6 +570,8 @@ public final class BinderProxy implements IBinder { try { return transactNative(code, data, reply, flags); } finally { AppOpsManager.resumeNotedAppOpsCollection(prevCollection); if (transactListener != null) { transactListener.onTransactEnded(session); } Loading core/java/android/permission/PermissionUsageHelper.java +72 −12 Original line number Diff line number Diff line Loading @@ -31,7 +31,9 @@ import static android.app.AppOpsManager.OPSTR_FINE_LOCATION; import static android.app.AppOpsManager.OPSTR_PHONE_CALL_CAMERA; import static android.app.AppOpsManager.OPSTR_PHONE_CALL_MICROPHONE; import static android.app.AppOpsManager.OPSTR_RECORD_AUDIO; import static android.app.AppOpsManager.OP_CAMERA; import static android.app.AppOpsManager.OP_FLAGS_ALL_TRUSTED; import static android.app.AppOpsManager.OP_RECORD_AUDIO; import static android.media.AudioSystem.MODE_IN_COMMUNICATION; import static android.telephony.TelephonyManager.CARRIER_PRIVILEGE_STATUS_HAS_ACCESS; Loading Loading @@ -63,7 +65,8 @@ import java.util.Objects; * * @hide */ public class PermissionUsageHelper implements AppOpsManager.OnOpActiveChangedListener { public class PermissionUsageHelper implements AppOpsManager.OnOpActiveChangedListener, AppOpsManager.OnOpStartedListener { /** Whether to show the mic and camera icons. */ private static final String PROPERTY_CAMERA_MIC_ICONS_ENABLED = "camera_mic_icons_enabled"; Loading Loading @@ -160,9 +163,10 @@ public class PermissionUsageHelper implements AppOpsManager.OnOpActiveChangedLis mUserContexts = new ArrayMap<>(); 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); String[] opStrs = { OPSTR_CAMERA, OPSTR_RECORD_AUDIO }; mAppOpsManager.startWatchingActive(opStrs, context.getMainExecutor(), this); int[] ops = { OP_CAMERA, OP_RECORD_AUDIO }; mAppOpsManager.startWatchingStarted(ops, this); } private Context getUserContext(UserHandle user) { Loading @@ -182,25 +186,65 @@ public class PermissionUsageHelper implements AppOpsManager.OnOpActiveChangedLis public void onOpActiveChanged(@NonNull String op, int uid, @NonNull String packageName, @Nullable String attributionTag, boolean active, @AttributionFlags int attributionFlags, int attributionChainId) { if (attributionChainId == ATTRIBUTION_CHAIN_ID_NONE || attributionFlags == ATTRIBUTION_FLAGS_NONE || (attributionFlags & ATTRIBUTION_FLAG_TRUSTED) == 0) { // If this is not a chain, or it is untrusted, return if (active) { // Started callback handles these return; } if (!active) { // if any link in the chain is finished, remove the chain. // if any link in the chain is finished, remove the chain. Then, find any other chains that // contain this op/package/uid/tag combination, and remove them, as well. // TODO ntmyren: be smarter about this mAttributionChains.remove(attributionChainId); int numChains = mAttributionChains.size(); ArrayList<Integer> toRemove = new ArrayList<>(); for (int i = 0; i < numChains; i++) { int chainId = mAttributionChains.keyAt(i); ArrayList<AccessChainLink> chain = mAttributionChains.valueAt(i); int chainSize = chain.size(); for (int j = 0; j < chainSize; j++) { AccessChainLink link = chain.get(j); if (link.packageAndOpEquals(op, packageName, attributionTag, uid)) { toRemove.add(chainId); break; } } } mAttributionChains.removeAll(toRemove); } @Override public void onOpStarted(int op, int uid, String packageName, String attributionTag, @AppOpsManager.OpFlags int flags, @AppOpsManager.Mode int result) { // not part of an attribution chain. Do nothing } @Override public void onOpStarted(int op, int uid, String packageName, String attributionTag, @AppOpsManager.OpFlags int flags, @AppOpsManager.Mode int result, @StartedType int startedType, @AttributionFlags int attributionFlags, int attributionChainId) { if (startedType == START_TYPE_FAILED || attributionChainId == ATTRIBUTION_CHAIN_ID_NONE || attributionFlags == ATTRIBUTION_FLAGS_NONE || (attributionFlags & ATTRIBUTION_FLAG_TRUSTED) == 0) { // If this is not a successful start, or it is not a chain, or it is untrusted, return return; } addLinkToChainIfNotPresent(AppOpsManager.opToPublicName(op), packageName, uid, attributionTag, attributionFlags, attributionChainId); } private void addLinkToChainIfNotPresent(String op, String packageName, int uid, String attributionTag, int attributionFlags, int attributionChainId) { ArrayList<AccessChainLink> currentChain = mAttributionChains.computeIfAbsent( attributionChainId, k -> new ArrayList<>()); AccessChainLink link = new AccessChainLink(op, packageName, attributionTag, uid, attributionFlags); if (currentChain.contains(link)) { return; } 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 Loading Loading @@ -613,5 +657,21 @@ public class PermissionUsageHelper implements AppOpsManager.OnOpActiveChangedLis public boolean isStart() { return (flags & ATTRIBUTION_FLAG_RECEIVER) != 0; } @Override public boolean equals(Object obj) { if (!(obj instanceof AccessChainLink)) { return false; } AccessChainLink other = (AccessChainLink) obj; return other.flags == flags && packageAndOpEquals(other.usage.op, other.usage.packageName, other.usage.attributionTag, other.usage.uid); } public boolean packageAndOpEquals(String op, String packageName, String attributionTag, int uid) { return Objects.equals(op, usage.op) && Objects.equals(packageName, usage.packageName) && Objects.equals(attributionTag, usage.attributionTag) && uid == usage.uid; } } } core/java/android/view/SurfaceView.java +1 −1 Original line number Diff line number Diff line Loading @@ -1242,7 +1242,7 @@ public class SurfaceView extends View implements ViewRootImpl.SurfaceChangedCall mBlastSurfaceControl.setTransformHint(mTransformHint); if (mBlastBufferQueue != null) { mBlastBufferQueue.update(mBlastSurfaceControl, mSurfaceWidth, mSurfaceHeight, mFormat); mFormat, transaction); } } else { transaction.setBufferSize(mSurfaceControl, mSurfaceWidth, mSurfaceHeight); Loading Loading
core/java/android/app/AppOpsManager.java +160 −103 Original line number Diff line number Diff line Loading @@ -2849,14 +2849,14 @@ public class AppOpsManager { private static final ThreadLocal<Integer> sBinderThreadCallingUid = new ThreadLocal<>(); /** * If a thread is currently executing a two-way binder transaction, this stores the * ops that were noted blaming any app (the caller, the caller of the caller, etc). * If a thread is currently executing a two-way binder transaction, this stores the op-codes of * the app-ops that were noted during this transaction. * * @see #getNotedOpCollectionMode * @see #collectNotedOpSync */ private static final ThreadLocal<ArrayMap<String, ArrayMap<String, long[]>>> sAppOpsNotedInThisBinderTransaction = new ThreadLocal<>(); private static final ThreadLocal<ArrayMap<String, long[]>> sAppOpsNotedInThisBinderTransaction = new ThreadLocal<>(); /** Whether noting for an appop should be collected */ private static final @ShouldCollectNoteOp byte[] sAppOpsToNote = new byte[_NUM_OP]; Loading Loading @@ -7205,6 +7205,34 @@ public class AppOpsManager { * @hide */ public interface OnOpStartedListener { /** * Represents a start operation that was unsuccessful * @hide */ public int START_TYPE_FAILED = 0; /** * Represents a successful start operation * @hide */ public int START_TYPE_STARTED = 1; /** * Represents an operation where a restricted operation became unrestricted, and resumed. * @hide */ public int START_TYPE_RESUMED = 2; /** @hide */ @Retention(RetentionPolicy.SOURCE) @IntDef(flag = true, prefix = { "TYPE_" }, value = { START_TYPE_FAILED, START_TYPE_STARTED, START_TYPE_RESUMED }) public @interface StartedType {} /** * Called when an op was started. * Loading @@ -7213,11 +7241,35 @@ public class AppOpsManager { * @param uid The UID performing the operation. * @param packageName The package performing the operation. * @param attributionTag The attribution tag performing the operation. * @param flags The flags of this op * @param flags The flags of this op. * @param result The result of the start. */ void onOpStarted(int op, int uid, String packageName, String attributionTag, @OpFlags int flags, @Mode int result); /** * Called when an op was started. * * Note: This is only for op starts. It is not called when an op is noted or stopped. * By default, unless this method is overridden, no code will be executed for resume * events. * @param op The op code. * @param uid The UID performing the operation. * @param packageName The package performing the operation. * @param attributionTag The attribution tag performing the operation. * @param flags The flags of this op. * @param result The result of the start. * @param startType The start type of this start event. Either failed, resumed, or started. * @param attributionFlags The location of this started op in an attribution chain. * @param attributionChainId The ID of the attribution chain of this op, if it is in one. */ default void onOpStarted(int op, int uid, String packageName, String attributionTag, @OpFlags int flags, @Mode int result, @StartedType int startType, @AttributionFlags int attributionFlags, int attributionChainId) { if (startType != START_TYPE_RESUMED) { onOpStarted(op, uid, packageName, attributionTag, flags, result); } } } AppOpsManager(Context context, IAppOpsService service) { Loading Loading @@ -7858,8 +7910,10 @@ public class AppOpsManager { cb = new IAppOpsStartedCallback.Stub() { @Override public void opStarted(int op, int uid, String packageName, String attributionTag, int flags, int mode) { callback.onOpStarted(op, uid, packageName, attributionTag, flags, mode); int flags, int mode, int startType, int attributionFlags, int attributionChainId) { callback.onOpStarted(op, uid, packageName, attributionTag, flags, mode, startType, attributionFlags, attributionChainId); } }; mStartedWatchers.put(callback, cb); Loading Loading @@ -9051,6 +9105,66 @@ public class AppOpsManager { sBinderThreadCallingUid.set(callingUid); } /** * State of a temporarily paused noted app-ops collection. * * @see #pauseNotedAppOpsCollection() * * @hide */ public static class PausedNotedAppOpsCollection { final int mUid; final @Nullable ArrayMap<String, long[]> mCollectedNotedAppOps; PausedNotedAppOpsCollection(int uid, @Nullable ArrayMap<String, long[]> collectedNotedAppOps) { mUid = uid; mCollectedNotedAppOps = collectedNotedAppOps; } } /** * Temporarily suspend collection of noted app-ops when binder-thread calls into the other * process. During such a call there might be call-backs coming back on the same thread which * should not be accounted to the current collection. * * @return a state needed to resume the collection * * @hide */ public static @Nullable PausedNotedAppOpsCollection pauseNotedAppOpsCollection() { Integer previousUid = sBinderThreadCallingUid.get(); if (previousUid != null) { ArrayMap<String, long[]> previousCollectedNotedAppOps = sAppOpsNotedInThisBinderTransaction.get(); sBinderThreadCallingUid.remove(); sAppOpsNotedInThisBinderTransaction.remove(); return new PausedNotedAppOpsCollection(previousUid, previousCollectedNotedAppOps); } return null; } /** * Resume a collection paused via {@link #pauseNotedAppOpsCollection}. * * @param prevCollection The state of the previous collection * * @hide */ public static void resumeNotedAppOpsCollection( @Nullable PausedNotedAppOpsCollection prevCollection) { if (prevCollection != null) { sBinderThreadCallingUid.set(prevCollection.mUid); if (prevCollection.mCollectedNotedAppOps != null) { sAppOpsNotedInThisBinderTransaction.set(prevCollection.mCollectedNotedAppOps); } } } /** * Finish collection of noted appops on this thread. * Loading Loading @@ -9091,47 +9205,26 @@ public class AppOpsManager { */ @TestApi public static void collectNotedOpSync(@NonNull SyncNotedAppOp syncOp) { collectNotedOpSync(sOpStrToOp.get(syncOp.getOp()), syncOp.getAttributionTag(), syncOp.getPackageName()); } /** * Collect a noted op when inside of a two-way binder call. * * <p> Delivered to caller via {@link #prefixParcelWithAppOpsIfNeeded} * * @param code the op code to note for * @param attributionTag the attribution tag to note for * @param packageName the package to note for */ private static void collectNotedOpSync(int code, @Nullable String attributionTag, @NonNull String packageName) { // If this is inside of a two-way binder call: // We are inside of a two-way binder call. Delivered to caller via // {@link #prefixParcelWithAppOpsIfNeeded} ArrayMap<String, ArrayMap<String, long[]>> appOpsNoted = sAppOpsNotedInThisBinderTransaction.get(); int op = sOpStrToOp.get(syncOp.getOp()); ArrayMap<String, long[]> appOpsNoted = sAppOpsNotedInThisBinderTransaction.get(); if (appOpsNoted == null) { appOpsNoted = new ArrayMap<>(1); sAppOpsNotedInThisBinderTransaction.set(appOpsNoted); } ArrayMap<String, long[]> packageAppOpsNotedForAttribution = appOpsNoted.get(packageName); if (packageAppOpsNotedForAttribution == null) { packageAppOpsNotedForAttribution = new ArrayMap<>(1); appOpsNoted.put(packageName, packageAppOpsNotedForAttribution); } long[] appOpsNotedForAttribution = packageAppOpsNotedForAttribution.get(attributionTag); long[] appOpsNotedForAttribution = appOpsNoted.get(syncOp.getAttributionTag()); if (appOpsNotedForAttribution == null) { appOpsNotedForAttribution = new long[2]; packageAppOpsNotedForAttribution.put(attributionTag, appOpsNotedForAttribution); appOpsNoted.put(syncOp.getAttributionTag(), appOpsNotedForAttribution); } if (code < 64) { appOpsNotedForAttribution[0] |= 1L << code; if (op < 64) { appOpsNotedForAttribution[0] |= 1L << op; } else { appOpsNotedForAttribution[1] |= 1L << (code - 64); appOpsNotedForAttribution[1] |= 1L << (op - 64); } } Loading Loading @@ -9185,7 +9278,9 @@ public class AppOpsManager { } } if (isListeningForOpNotedInBinderTransaction()) { Integer binderUid = sBinderThreadCallingUid.get(); if (binderUid != null && binderUid == uid) { return COLLECT_SYNC; } else { return COLLECT_ASYNC; Loading @@ -9204,32 +9299,20 @@ public class AppOpsManager { */ // TODO (b/186872903) Refactor how sync noted ops are propagated. public static void prefixParcelWithAppOpsIfNeeded(@NonNull Parcel p) { if (!isListeningForOpNotedInBinderTransaction()) { return; } final ArrayMap<String, ArrayMap<String, long[]>> notedAppOps = sAppOpsNotedInThisBinderTransaction.get(); ArrayMap<String, long[]> notedAppOps = sAppOpsNotedInThisBinderTransaction.get(); if (notedAppOps == null) { return; } p.writeInt(Parcel.EX_HAS_NOTED_APPOPS_REPLY_HEADER); final int packageCount = notedAppOps.size(); p.writeInt(packageCount); int numAttributionWithNotesAppOps = notedAppOps.size(); p.writeInt(numAttributionWithNotesAppOps); for (int i = 0; i < packageCount; i++) { for (int i = 0; i < numAttributionWithNotesAppOps; i++) { p.writeString(notedAppOps.keyAt(i)); final ArrayMap<String, long[]> notedTagAppOps = notedAppOps.valueAt(i); final int tagCount = notedTagAppOps.size(); p.writeInt(tagCount); for (int j = 0; j < tagCount; j++) { p.writeString(notedTagAppOps.keyAt(j)); p.writeLong(notedTagAppOps.valueAt(j)[0]); p.writeLong(notedTagAppOps.valueAt(j)[1]); } p.writeLong(notedAppOps.valueAt(i)[0]); p.writeLong(notedAppOps.valueAt(i)[1]); } } Loading @@ -9244,54 +9327,36 @@ public class AppOpsManager { * @hide */ public static void readAndLogNotedAppops(@NonNull Parcel p) { final int packageCount = p.readInt(); if (packageCount <= 0) { return; } int numAttributionsWithNotedAppOps = p.readInt(); final String myPackageName = ActivityThread.currentPackageName(); synchronized (sLock) { for (int i = 0; i < packageCount; i++) { final String packageName = p.readString(); final int tagCount = p.readInt(); for (int j = 0; j < tagCount; j++) { final String attributionTag = p.readString(); final long[] rawNotedAppOps = new long[2]; for (int i = 0; i < numAttributionsWithNotedAppOps; i++) { String attributionTag = p.readString(); long[] rawNotedAppOps = new long[2]; rawNotedAppOps[0] = p.readLong(); rawNotedAppOps[1] = p.readLong(); if (rawNotedAppOps[0] == 0 && rawNotedAppOps[1] == 0) { continue; } if (rawNotedAppOps[0] != 0 || rawNotedAppOps[1] != 0) { BitSet notedAppOps = BitSet.valueOf(rawNotedAppOps); final BitSet notedAppOps = BitSet.valueOf(rawNotedAppOps); synchronized (sLock) { for (int code = notedAppOps.nextSetBit(0); code != -1; code = notedAppOps.nextSetBit(code + 1)) { if (Objects.equals(myPackageName, packageName)) { if (sOnOpNotedCallback != null) { sOnOpNotedCallback.onNoted(new SyncNotedAppOp(code, attributionTag, packageName)); sOnOpNotedCallback.onNoted(new SyncNotedAppOp(code, attributionTag)); } else { String message = getFormattedStackTrace(); sUnforwardedOps.add(new AsyncNotedAppOp(code, Process.myUid(), attributionTag, message, System.currentTimeMillis())); sUnforwardedOps.add( new AsyncNotedAppOp(code, Process.myUid(), attributionTag, message, System.currentTimeMillis())); if (sUnforwardedOps.size() > MAX_UNFORWARDED_OPS) { sUnforwardedOps.remove(0); } } } else if (isListeningForOpNotedInBinderTransaction()) { collectNotedOpSync(code, attributionTag, packageName); } } for (int code = notedAppOps.nextSetBit(0); code != -1; code = notedAppOps.nextSetBit(code + 1)) { if (Objects.equals(myPackageName, packageName)) { sMessageCollector.onNoted(new SyncNotedAppOp(code, attributionTag, packageName)); } } sMessageCollector.onNoted(new SyncNotedAppOp(code, attributionTag)); } } } Loading Loading @@ -9398,15 +9463,7 @@ public class AppOpsManager { * @hide */ public static boolean isListeningForOpNoted() { return sOnOpNotedCallback != null || isListeningForOpNotedInBinderTransaction() || isCollectingStackTraces(); } /** * @return whether we are in a binder transaction and collecting appops. */ private static boolean isListeningForOpNotedInBinderTransaction() { return sBinderThreadCallingUid.get() != null; return sOnOpNotedCallback != null || isCollectingStackTraces(); } /** Loading
core/java/android/app/SyncNotedAppOp.java +2 −1 Original line number Diff line number Diff line Loading @@ -21,7 +21,6 @@ import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.TestApi; import android.os.Parcelable; import android.os.Process; import com.android.internal.annotations.Immutable; import com.android.internal.util.DataClass; Loading @@ -29,6 +28,8 @@ import com.android.internal.util.DataClass; /** * Description of an app-op that was noted for the current process. * * Note: package name is currently unused in the system. * * <p>This is either delivered after a * {@link AppOpsManager.OnOpNotedCallback#onNoted(SyncNotedAppOp) two way binder call} or * when the app Loading
core/java/android/os/BinderProxy.java +5 −0 Original line number Diff line number Diff line Loading @@ -560,6 +560,9 @@ public final class BinderProxy implements IBinder { } } final AppOpsManager.PausedNotedAppOpsCollection prevCollection = AppOpsManager.pauseNotedAppOpsCollection(); if ((flags & FLAG_ONEWAY) == 0 && AppOpsManager.isListeningForOpNoted()) { flags |= FLAG_COLLECT_NOTED_APP_OPS; } Loading @@ -567,6 +570,8 @@ public final class BinderProxy implements IBinder { try { return transactNative(code, data, reply, flags); } finally { AppOpsManager.resumeNotedAppOpsCollection(prevCollection); if (transactListener != null) { transactListener.onTransactEnded(session); } Loading
core/java/android/permission/PermissionUsageHelper.java +72 −12 Original line number Diff line number Diff line Loading @@ -31,7 +31,9 @@ import static android.app.AppOpsManager.OPSTR_FINE_LOCATION; import static android.app.AppOpsManager.OPSTR_PHONE_CALL_CAMERA; import static android.app.AppOpsManager.OPSTR_PHONE_CALL_MICROPHONE; import static android.app.AppOpsManager.OPSTR_RECORD_AUDIO; import static android.app.AppOpsManager.OP_CAMERA; import static android.app.AppOpsManager.OP_FLAGS_ALL_TRUSTED; import static android.app.AppOpsManager.OP_RECORD_AUDIO; import static android.media.AudioSystem.MODE_IN_COMMUNICATION; import static android.telephony.TelephonyManager.CARRIER_PRIVILEGE_STATUS_HAS_ACCESS; Loading Loading @@ -63,7 +65,8 @@ import java.util.Objects; * * @hide */ public class PermissionUsageHelper implements AppOpsManager.OnOpActiveChangedListener { public class PermissionUsageHelper implements AppOpsManager.OnOpActiveChangedListener, AppOpsManager.OnOpStartedListener { /** Whether to show the mic and camera icons. */ private static final String PROPERTY_CAMERA_MIC_ICONS_ENABLED = "camera_mic_icons_enabled"; Loading Loading @@ -160,9 +163,10 @@ public class PermissionUsageHelper implements AppOpsManager.OnOpActiveChangedLis mUserContexts = new ArrayMap<>(); 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); String[] opStrs = { OPSTR_CAMERA, OPSTR_RECORD_AUDIO }; mAppOpsManager.startWatchingActive(opStrs, context.getMainExecutor(), this); int[] ops = { OP_CAMERA, OP_RECORD_AUDIO }; mAppOpsManager.startWatchingStarted(ops, this); } private Context getUserContext(UserHandle user) { Loading @@ -182,25 +186,65 @@ public class PermissionUsageHelper implements AppOpsManager.OnOpActiveChangedLis public void onOpActiveChanged(@NonNull String op, int uid, @NonNull String packageName, @Nullable String attributionTag, boolean active, @AttributionFlags int attributionFlags, int attributionChainId) { if (attributionChainId == ATTRIBUTION_CHAIN_ID_NONE || attributionFlags == ATTRIBUTION_FLAGS_NONE || (attributionFlags & ATTRIBUTION_FLAG_TRUSTED) == 0) { // If this is not a chain, or it is untrusted, return if (active) { // Started callback handles these return; } if (!active) { // if any link in the chain is finished, remove the chain. // if any link in the chain is finished, remove the chain. Then, find any other chains that // contain this op/package/uid/tag combination, and remove them, as well. // TODO ntmyren: be smarter about this mAttributionChains.remove(attributionChainId); int numChains = mAttributionChains.size(); ArrayList<Integer> toRemove = new ArrayList<>(); for (int i = 0; i < numChains; i++) { int chainId = mAttributionChains.keyAt(i); ArrayList<AccessChainLink> chain = mAttributionChains.valueAt(i); int chainSize = chain.size(); for (int j = 0; j < chainSize; j++) { AccessChainLink link = chain.get(j); if (link.packageAndOpEquals(op, packageName, attributionTag, uid)) { toRemove.add(chainId); break; } } } mAttributionChains.removeAll(toRemove); } @Override public void onOpStarted(int op, int uid, String packageName, String attributionTag, @AppOpsManager.OpFlags int flags, @AppOpsManager.Mode int result) { // not part of an attribution chain. Do nothing } @Override public void onOpStarted(int op, int uid, String packageName, String attributionTag, @AppOpsManager.OpFlags int flags, @AppOpsManager.Mode int result, @StartedType int startedType, @AttributionFlags int attributionFlags, int attributionChainId) { if (startedType == START_TYPE_FAILED || attributionChainId == ATTRIBUTION_CHAIN_ID_NONE || attributionFlags == ATTRIBUTION_FLAGS_NONE || (attributionFlags & ATTRIBUTION_FLAG_TRUSTED) == 0) { // If this is not a successful start, or it is not a chain, or it is untrusted, return return; } addLinkToChainIfNotPresent(AppOpsManager.opToPublicName(op), packageName, uid, attributionTag, attributionFlags, attributionChainId); } private void addLinkToChainIfNotPresent(String op, String packageName, int uid, String attributionTag, int attributionFlags, int attributionChainId) { ArrayList<AccessChainLink> currentChain = mAttributionChains.computeIfAbsent( attributionChainId, k -> new ArrayList<>()); AccessChainLink link = new AccessChainLink(op, packageName, attributionTag, uid, attributionFlags); if (currentChain.contains(link)) { return; } 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 Loading Loading @@ -613,5 +657,21 @@ public class PermissionUsageHelper implements AppOpsManager.OnOpActiveChangedLis public boolean isStart() { return (flags & ATTRIBUTION_FLAG_RECEIVER) != 0; } @Override public boolean equals(Object obj) { if (!(obj instanceof AccessChainLink)) { return false; } AccessChainLink other = (AccessChainLink) obj; return other.flags == flags && packageAndOpEquals(other.usage.op, other.usage.packageName, other.usage.attributionTag, other.usage.uid); } public boolean packageAndOpEquals(String op, String packageName, String attributionTag, int uid) { return Objects.equals(op, usage.op) && Objects.equals(packageName, usage.packageName) && Objects.equals(attributionTag, usage.attributionTag) && uid == usage.uid; } } }
core/java/android/view/SurfaceView.java +1 −1 Original line number Diff line number Diff line Loading @@ -1242,7 +1242,7 @@ public class SurfaceView extends View implements ViewRootImpl.SurfaceChangedCall mBlastSurfaceControl.setTransformHint(mTransformHint); if (mBlastBufferQueue != null) { mBlastBufferQueue.update(mBlastSurfaceControl, mSurfaceWidth, mSurfaceHeight, mFormat); mFormat, transaction); } } else { transaction.setBufferSize(mSurfaceControl, mSurfaceWidth, mSurfaceHeight); Loading