diff --git a/services/core/java/com/android/server/appop/AppOpsService.java b/services/core/java/com/android/server/appop/AppOpsService.java index 3d5711ff20f98..b844fc6b43ab4 100644 --- a/services/core/java/com/android/server/appop/AppOpsService.java +++ b/services/core/java/com/android/server/appop/AppOpsService.java @@ -68,7 +68,6 @@ import static android.content.pm.PermissionInfo.PROTECTION_FLAG_APPOP; import static com.android.server.appop.AppOpsService.ModeCallback.ALL_OPS; import android.Manifest; -import android.annotation.IntRange; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.UserIdInt; @@ -129,8 +128,6 @@ import android.util.AtomicFile; import android.util.IndentingPrintWriter; import android.util.KeyValueListParser; import android.util.Pair; -import android.util.Pools; -import android.util.Pools.SimplePool; import android.util.Slog; import android.util.SparseArray; import android.util.SparseBooleanArray; @@ -194,7 +191,6 @@ import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; -import java.util.NoSuchElementException; import java.util.Objects; import java.util.Scanner; import java.util.Set; @@ -237,14 +233,22 @@ public class AppOpsService extends IAppOpsService.Stub implements PersistenceSch private final @Nullable File mNoteOpCallerStacktracesFile; final Handler mHandler; - /** Pool for {@link OpEventProxyInfoPool} to avoid to constantly reallocate new objects */ + /** + * Pool for {@link AttributedOp.OpEventProxyInfoPool} to avoid to constantly reallocate new + * objects + */ @GuardedBy("this") - final OpEventProxyInfoPool mOpEventProxyInfoPool = new OpEventProxyInfoPool(); + final AttributedOp.OpEventProxyInfoPool mOpEventProxyInfoPool = + new AttributedOp.OpEventProxyInfoPool(MAX_UNUSED_POOLED_OBJECTS); - /** Pool for {@link InProgressStartOpEventPool} to avoid to constantly reallocate new objects */ + /** + * Pool for {@link AttributedOp.InProgressStartOpEventPool} to avoid to constantly reallocate + * new objects + */ @GuardedBy("this") - final InProgressStartOpEventPool mInProgressStartOpEventPool = - new InProgressStartOpEventPool(); + final AttributedOp.InProgressStartOpEventPool mInProgressStartOpEventPool = + new AttributedOp.InProgressStartOpEventPool(mOpEventProxyInfoPool, + MAX_UNUSED_POOLED_OBJECTS); private final AppOpsManagerInternalImpl mAppOpsManagerInternal = new AppOpsManagerInternalImpl(); @@ -378,60 +382,6 @@ public class AppOpsService extends IAppOpsService.Stub implements PersistenceSch return mUidStateTracker; } - /** - * An unsynchronized pool of {@link OpEventProxyInfo} objects. - */ - class OpEventProxyInfoPool extends SimplePool { - OpEventProxyInfoPool() { - super(MAX_UNUSED_POOLED_OBJECTS); - } - - OpEventProxyInfo acquire(@IntRange(from = 0) int uid, @Nullable String packageName, - @Nullable String attributionTag) { - OpEventProxyInfo recycled = acquire(); - if (recycled != null) { - recycled.reinit(uid, packageName, attributionTag); - return recycled; - } - - return new OpEventProxyInfo(uid, packageName, attributionTag); - } - } - - /** - * An unsynchronized pool of {@link InProgressStartOpEvent} objects. - */ - class InProgressStartOpEventPool extends SimplePool { - InProgressStartOpEventPool() { - super(MAX_UNUSED_POOLED_OBJECTS); - } - - InProgressStartOpEvent acquire(long startTime, long elapsedTime, @NonNull IBinder clientId, - @Nullable String attributionTag, @NonNull Runnable onDeath, int proxyUid, - @Nullable String proxyPackageName, @Nullable String proxyAttributionTag, - @AppOpsManager.UidState int uidState, @OpFlags int flags, @AttributionFlags - int attributionFlags, int attributionChainId) throws RemoteException { - - InProgressStartOpEvent recycled = acquire(); - - OpEventProxyInfo proxyInfo = null; - if (proxyUid != Process.INVALID_UID) { - proxyInfo = mOpEventProxyInfoPool.acquire(proxyUid, proxyPackageName, - proxyAttributionTag); - } - - if (recycled != null) { - recycled.reinit(startTime, elapsedTime, clientId, attributionTag, onDeath, - uidState, flags, proxyInfo, attributionFlags, attributionChainId, - mOpEventProxyInfoPool); - return recycled; - } - - return new InProgressStartOpEvent(startTime, elapsedTime, clientId, attributionTag, - onDeath, uidState, proxyInfo, flags, attributionFlags, attributionChainId); - } - } - /** * All times are in milliseconds. These constants are kept synchronized with the system * global Settings. Any access to this class or its fields should be done while @@ -648,181 +598,6 @@ public class AppOpsService extends IAppOpsService.Stub implements PersistenceSch } } - /** A in progress startOp->finishOp event */ - static final class InProgressStartOpEvent implements IBinder.DeathRecipient { - /** Wall clock time of startOp event (not monotonic) */ - private long mStartTime; - - /** Elapsed time since boot of startOp event */ - private long mStartElapsedTime; - - /** Id of the client that started the event */ - private @NonNull IBinder mClientId; - - /** The attribution tag for this operation */ - private @Nullable String mAttributionTag; - - /** To call when client dies */ - private @NonNull Runnable mOnDeath; - - /** uidstate used when calling startOp */ - private @AppOpsManager.UidState int mUidState; - - /** Proxy information of the startOp event */ - private @Nullable OpEventProxyInfo mProxy; - - /** Proxy flag information */ - private @OpFlags int mFlags; - - /** How many times the op was started but not finished yet */ - int numUnfinishedStarts; - - /** The attribution flags related to this event */ - private @AttributionFlags int mAttributionFlags; - - /** The id of the attribution chain this even is a part of */ - private int mAttributionChainId; - - /** - * Create a new {@link InProgressStartOpEvent}. - * - * @param startTime The time {@link #startOperation} was called - * @param startElapsedTime The elapsed time when {@link #startOperation} was called - * @param clientId The client id of the caller of {@link #startOperation} - * @param attributionTag The attribution tag for the operation. - * @param onDeath The code to execute on client death - * @param uidState The uidstate of the app {@link #startOperation} was called for - * @param attributionFlags the attribution flags for this operation. - * @param attributionChainId the unique id of the attribution chain this op is a part of. - * @param proxy The proxy information, if {@link #startProxyOperation} was called - * @param flags The trusted/nontrusted/self flags. - * - * @throws RemoteException If the client is dying - */ - private InProgressStartOpEvent(long startTime, long startElapsedTime, - @NonNull IBinder clientId, @Nullable String attributionTag, - @NonNull Runnable onDeath, @AppOpsManager.UidState int uidState, - @Nullable OpEventProxyInfo proxy, @OpFlags int flags, - @AttributionFlags int attributionFlags, int attributionChainId) - throws RemoteException { - mStartTime = startTime; - mStartElapsedTime = startElapsedTime; - mClientId = clientId; - mAttributionTag = attributionTag; - mOnDeath = onDeath; - mUidState = uidState; - mProxy = proxy; - mFlags = flags; - mAttributionFlags = attributionFlags; - mAttributionChainId = attributionChainId; - - clientId.linkToDeath(this, 0); - } - - /** Clean up event */ - public void finish() { - try { - mClientId.unlinkToDeath(this, 0); - } catch (NoSuchElementException e) { - // Either not linked, or already unlinked. Either way, nothing to do. - } - } - - @Override - public void binderDied() { - mOnDeath.run(); - } - - /** - * Reinit existing object with new state. - * - * @param startTime The time {@link #startOperation} was called - * @param startElapsedTime The elapsed time when {@link #startOperation} was called - * @param clientId The client id of the caller of {@link #startOperation} - * @param attributionTag The attribution tag for this operation. - * @param onDeath The code to execute on client death - * @param uidState The uidstate of the app {@link #startOperation} was called for - * @param flags The flags relating to the proxy - * @param proxy The proxy information, if {@link #startProxyOperation} was called - * @param attributionFlags the attribution flags for this operation. - * @param attributionChainId the unique id of the attribution chain this op is a part of. - * @param proxyPool The pool to release previous {@link OpEventProxyInfo} to - * - * @throws RemoteException If the client is dying - */ - public void reinit(long startTime, long startElapsedTime, @NonNull IBinder clientId, - @Nullable String attributionTag, @NonNull Runnable onDeath, - @AppOpsManager.UidState int uidState, @OpFlags int flags, - @Nullable OpEventProxyInfo proxy, @AttributionFlags int attributionFlags, - int attributionChainId, @NonNull Pools.Pool proxyPool - ) throws RemoteException { - mStartTime = startTime; - mStartElapsedTime = startElapsedTime; - mClientId = clientId; - mAttributionTag = attributionTag; - mOnDeath = onDeath; - mUidState = uidState; - mFlags = flags; - - if (mProxy != null) { - proxyPool.release(mProxy); - } - mProxy = proxy; - mAttributionFlags = attributionFlags; - mAttributionChainId = attributionChainId; - - clientId.linkToDeath(this, 0); - } - - /** @return Wall clock time of startOp event */ - public long getStartTime() { - return mStartTime; - } - - /** @return Elapsed time since boot of startOp event */ - public long getStartElapsedTime() { - return mStartElapsedTime; - } - - /** @return Id of the client that started the event */ - public @NonNull IBinder getClientId() { - return mClientId; - } - - /** @return uidstate used when calling startOp */ - public @AppOpsManager.UidState int getUidState() { - return mUidState; - } - - /** @return proxy tag for the access */ - public @Nullable OpEventProxyInfo getProxy() { - return mProxy; - } - - /** @return flags used for the access */ - public @OpFlags int getFlags() { - return mFlags; - } - - /** @return attributoin flags used for the access */ - public @AttributionFlags int getAttributionFlags() { - return mAttributionFlags; - } - - /** @return attribution chain id for the access */ - public int getAttributionChainId() { - return mAttributionChainId; - } - - public void setStartTime(long startTime) { - mStartTime = startTime; - } - - public void setStartElapsedTime(long startElapsedTime) { - mStartElapsedTime = startElapsedTime; - } - } - final class Op { int op; int uid; @@ -5137,10 +4912,11 @@ public class AppOpsService extends IAppOpsService.Stub implements PersistenceSch long maxNumStarts = 0; int numInProgressEvents = attributedOp.mInProgressEvents.size(); for (int i = 0; i < numInProgressEvents; i++) { - InProgressStartOpEvent event = attributedOp.mInProgressEvents.valueAt(i); + AttributedOp.InProgressStartOpEvent event = + attributedOp.mInProgressEvents.valueAt(i); earliestElapsedTime = Math.min(earliestElapsedTime, event.getStartElapsedTime()); - maxNumStarts = Math.max(maxNumStarts, event.numUnfinishedStarts); + maxNumStarts = Math.max(maxNumStarts, event.mNumUnfinishedStarts); } pw.print(prefix + "Running start at: "); diff --git a/services/core/java/com/android/server/appop/AttributedOp.java b/services/core/java/com/android/server/appop/AttributedOp.java index c37876bc889f7..dcc36bcf6149c 100644 --- a/services/core/java/com/android/server/appop/AttributedOp.java +++ b/services/core/java/com/android/server/appop/AttributedOp.java @@ -20,6 +20,7 @@ import static android.app.AppOpsManager.MODE_ALLOWED; import static android.app.AppOpsManager.OnOpStartedListener.START_TYPE_RESUMED; import static android.app.AppOpsManager.makeKey; +import android.annotation.IntRange; import android.annotation.NonNull; import android.annotation.Nullable; import android.app.AppOpsManager; @@ -29,13 +30,14 @@ import android.os.RemoteException; import android.os.SystemClock; import android.util.ArrayMap; import android.util.LongSparseArray; +import android.util.Pools; import android.util.Slog; -import com.android.internal.annotations.GuardedBy; import com.android.internal.util.function.pooled.PooledLambda; import java.util.ArrayList; import java.util.List; +import java.util.NoSuchElementException; final class AttributedOp { private final @NonNull AppOpsService mAppOpsService; @@ -47,7 +49,8 @@ final class AttributedOp { * *

Key is {@link AppOpsManager#makeKey} */ - @GuardedBy("mAppOpsService") + // TODO(b/248108338) + // @GuardedBy("mAppOpsService") private @Nullable LongSparseArray mAccessEvents; /** @@ -55,7 +58,8 @@ final class AttributedOp { * *

Key is {@link AppOpsManager#makeKey} */ - @GuardedBy("mAppOpsService") + // TODO(b/248108338) + // @GuardedBy("mAppOpsService") private @Nullable LongSparseArray mRejectEvents; /** @@ -63,16 +67,18 @@ final class AttributedOp { * *

Key is clientId */ - @GuardedBy("mAppOpsService") - @Nullable ArrayMap mInProgressEvents; + // TODO(b/248108338) + // @GuardedBy("mAppOpsService") + @Nullable ArrayMap mInProgressEvents; /** * Currently paused startOp events * *

Key is clientId */ - @GuardedBy("mAppOpsService") - @Nullable ArrayMap mPausedInProgressEvents; + // TODO(b/248108338) + // @GuardedBy("mAppOpsService") + @Nullable ArrayMap mPausedInProgressEvents; AttributedOp(@NonNull AppOpsService appOpsService, @Nullable String tag, @NonNull AppOpsService.Op parent) { @@ -224,11 +230,11 @@ final class AttributedOp { } else if (!isStarted && mPausedInProgressEvents == null) { mPausedInProgressEvents = new ArrayMap<>(1); } - ArrayMap events = isStarted + ArrayMap events = isStarted ? mInProgressEvents : mPausedInProgressEvents; long startTime = System.currentTimeMillis(); - AppOpsService.InProgressStartOpEvent event = events.get(clientId); + InProgressStartOpEvent event = events.get(clientId); if (event == null) { event = mAppOpsService.mInProgressStartOpEventPool.acquire(startTime, SystemClock.elapsedRealtime(), clientId, tag, @@ -242,7 +248,7 @@ final class AttributedOp { } } - event.numUnfinishedStarts++; + event.mNumUnfinishedStarts++; if (isStarted) { mAppOpsService.mHistoricalRegistry.incrementOpAccessedCount(parent.op, parent.uid, @@ -277,12 +283,12 @@ final class AttributedOp { return; } - AppOpsService.InProgressStartOpEvent event = mInProgressEvents.valueAt(indexOfToken); + InProgressStartOpEvent event = mInProgressEvents.valueAt(indexOfToken); if (!isPausing) { - event.numUnfinishedStarts--; + event.mNumUnfinishedStarts--; } // If we are pausing, create a NoteOpEvent, but don't change the InProgress event - if (event.numUnfinishedStarts == 0 || isPausing) { + if (event.mNumUnfinishedStarts == 0 || isPausing) { if (!isPausing) { event.finish(); mInProgressEvents.removeAt(indexOfToken); @@ -342,9 +348,9 @@ final class AttributedOp { } // no need to record a paused event finishing. - AppOpsService.InProgressStartOpEvent event = mPausedInProgressEvents.valueAt(indexOfToken); - event.numUnfinishedStarts--; - if (event.numUnfinishedStarts == 0) { + InProgressStartOpEvent event = mPausedInProgressEvents.valueAt(indexOfToken); + event.mNumUnfinishedStarts--; + if (event.mNumUnfinishedStarts == 0) { mPausedInProgressEvents.removeAt(indexOfToken); mAppOpsService.mInProgressStartOpEventPool.release(event); if (mPausedInProgressEvents.isEmpty()) { @@ -378,7 +384,7 @@ final class AttributedOp { } for (int i = 0; i < mInProgressEvents.size(); i++) { - AppOpsService.InProgressStartOpEvent event = mInProgressEvents.valueAt(i); + InProgressStartOpEvent event = mInProgressEvents.valueAt(i); mPausedInProgressEvents.put(event.getClientId(), event); finishOrPause(event.getClientId(), true, true); @@ -406,7 +412,7 @@ final class AttributedOp { long startTime = System.currentTimeMillis(); for (int i = 0; i < mPausedInProgressEvents.size(); i++) { - AppOpsService.InProgressStartOpEvent event = mPausedInProgressEvents.valueAt(i); + InProgressStartOpEvent event = mPausedInProgressEvents.valueAt(i); mInProgressEvents.put(event.getClientId(), event); event.setStartElapsedTime(SystemClock.elapsedRealtime()); event.setStartTime(startTime); @@ -438,11 +444,11 @@ final class AttributedOp { return; } - ArrayMap events = isPaused() + ArrayMap events = isPaused() ? mPausedInProgressEvents : mInProgressEvents; - AppOpsService.InProgressStartOpEvent deadEvent = events.get(clientId); + InProgressStartOpEvent deadEvent = events.get(clientId); if (deadEvent != null) { - deadEvent.numUnfinishedStarts = 1; + deadEvent.mNumUnfinishedStarts = 1; } finished(clientId); @@ -460,20 +466,20 @@ final class AttributedOp { } boolean isRunning = isRunning(); - ArrayMap events = + ArrayMap events = isRunning ? mInProgressEvents : mPausedInProgressEvents; int numInProgressEvents = events.size(); List binders = new ArrayList<>(events.keySet()); for (int i = 0; i < numInProgressEvents; i++) { - AppOpsService.InProgressStartOpEvent event = events.get(binders.get(i)); + InProgressStartOpEvent event = events.get(binders.get(i)); if (event != null && event.getUidState() != newState) { try { // Remove all but one unfinished start count and then call finished() to // remove start event object - int numPreviousUnfinishedStarts = event.numUnfinishedStarts; - event.numUnfinishedStarts = 1; + int numPreviousUnfinishedStarts = event.mNumUnfinishedStarts; + event.mNumUnfinishedStarts = 1; AppOpsManager.OpEventProxyInfo proxy = event.getProxy(); finished(event.getClientId(), false); @@ -492,9 +498,9 @@ final class AttributedOp { } events = isRunning ? mInProgressEvents : mPausedInProgressEvents; - AppOpsService.InProgressStartOpEvent newEvent = events.get(binders.get(i)); + InProgressStartOpEvent newEvent = events.get(binders.get(i)); if (newEvent != null) { - newEvent.numUnfinishedStarts += numPreviousUnfinishedStarts - 1; + newEvent.mNumUnfinishedStarts += numPreviousUnfinishedStarts - 1; } } catch (RemoteException e) { if (AppOpsService.DEBUG) { @@ -546,7 +552,7 @@ final class AttributedOp { @SuppressWarnings("GuardedBy") // Lock is held on mAppOpsService public void add(@NonNull AttributedOp opToAdd) { if (opToAdd.isRunning() || opToAdd.isPaused()) { - ArrayMap ignoredEvents = + ArrayMap ignoredEvents = opToAdd.isRunning() ? opToAdd.mInProgressEvents : opToAdd.mPausedInProgressEvents; Slog.w(AppOpsService.TAG, "Ignoring " + ignoredEvents.size() + " app-ops, running: " @@ -554,7 +560,7 @@ final class AttributedOp { int numInProgressEvents = ignoredEvents.size(); for (int i = 0; i < numInProgressEvents; i++) { - AppOpsService.InProgressStartOpEvent event = ignoredEvents.valueAt(i); + InProgressStartOpEvent event = ignoredEvents.valueAt(i); event.finish(); mAppOpsService.mInProgressStartOpEventPool.release(event); @@ -609,7 +615,7 @@ final class AttributedOp { } for (int i = 0; i < numInProgressEvents; i++) { - AppOpsService.InProgressStartOpEvent event = mInProgressEvents.valueAt(i); + InProgressStartOpEvent event = mInProgressEvents.valueAt(i); accessEvents.append(makeKey(event.getUidState(), event.getFlags()), new AppOpsManager.NoteOpEvent(event.getStartTime(), @@ -623,4 +629,242 @@ final class AttributedOp { return new AppOpsManager.AttributedOpEntry(parent.op, isRunning(), accessEvents, rejectEvents); } + + /** A in progress startOp->finishOp event */ + static final class InProgressStartOpEvent implements IBinder.DeathRecipient { + /** Wall clock time of startOp event (not monotonic) */ + private long mStartTime; + + /** Elapsed time since boot of startOp event */ + private long mStartElapsedTime; + + /** Id of the client that started the event */ + private @NonNull IBinder mClientId; + + /** The attribution tag for this operation */ + private @Nullable String mAttributionTag; + + /** To call when client dies */ + private @NonNull Runnable mOnDeath; + + /** uidstate used when calling startOp */ + private @AppOpsManager.UidState int mUidState; + + /** Proxy information of the startOp event */ + private @Nullable AppOpsManager.OpEventProxyInfo mProxy; + + /** Proxy flag information */ + private @AppOpsManager.OpFlags int mFlags; + + /** How many times the op was started but not finished yet */ + int mNumUnfinishedStarts; + + /** The attribution flags related to this event */ + private @AppOpsManager.AttributionFlags int mAttributionFlags; + + /** The id of the attribution chain this even is a part of */ + private int mAttributionChainId; + + /** + * Create a new {@link InProgressStartOpEvent}. + * + * @param startTime The time {@link #startOperation} was called + * @param startElapsedTime The elapsed time when {@link #startOperation} was called + * @param clientId The client id of the caller of {@link #startOperation} + * @param attributionTag The attribution tag for the operation. + * @param onDeath The code to execute on client death + * @param uidState The uidstate of the app {@link #startOperation} was called for + * @param attributionFlags the attribution flags for this operation. + * @param attributionChainId the unique id of the attribution chain this op is a part of. + * @param proxy The proxy information, if {@link #startProxyOperation} was + * called + * @param flags The trusted/nontrusted/self flags. + * @throws RemoteException If the client is dying + */ + InProgressStartOpEvent(long startTime, long startElapsedTime, + @NonNull IBinder clientId, @Nullable String attributionTag, + @NonNull Runnable onDeath, @AppOpsManager.UidState int uidState, + @Nullable AppOpsManager.OpEventProxyInfo proxy, @AppOpsManager.OpFlags int flags, + @AppOpsManager.AttributionFlags int attributionFlags, int attributionChainId) + throws RemoteException { + mStartTime = startTime; + mStartElapsedTime = startElapsedTime; + mClientId = clientId; + mAttributionTag = attributionTag; + mOnDeath = onDeath; + mUidState = uidState; + mProxy = proxy; + mFlags = flags; + mAttributionFlags = attributionFlags; + mAttributionChainId = attributionChainId; + + clientId.linkToDeath(this, 0); + } + + /** Clean up event */ + public void finish() { + try { + mClientId.unlinkToDeath(this, 0); + } catch (NoSuchElementException e) { + // Either not linked, or already unlinked. Either way, nothing to do. + } + } + + @Override + public void binderDied() { + mOnDeath.run(); + } + + /** + * Reinit existing object with new state. + * + * @param startTime The time {@link #startOperation} was called + * @param startElapsedTime The elapsed time when {@link #startOperation} was called + * @param clientId The client id of the caller of {@link #startOperation} + * @param attributionTag The attribution tag for this operation. + * @param onDeath The code to execute on client death + * @param uidState The uidstate of the app {@link #startOperation} was called for + * @param flags The flags relating to the proxy + * @param proxy The proxy information, if {@link #startProxyOperation} + * was called + * @param attributionFlags the attribution flags for this operation. + * @param attributionChainId the unique id of the attribution chain this op is a part of. + * @param proxyPool The pool to release + * previous {@link AppOpsManager.OpEventProxyInfo} to + * @throws RemoteException If the client is dying + */ + public void reinit(long startTime, long startElapsedTime, @NonNull IBinder clientId, + @Nullable String attributionTag, @NonNull Runnable onDeath, + @AppOpsManager.UidState int uidState, @AppOpsManager.OpFlags int flags, + @Nullable AppOpsManager.OpEventProxyInfo proxy, + @AppOpsManager.AttributionFlags int attributionFlags, + int attributionChainId, + @NonNull Pools.Pool proxyPool + ) throws RemoteException { + mStartTime = startTime; + mStartElapsedTime = startElapsedTime; + mClientId = clientId; + mAttributionTag = attributionTag; + mOnDeath = onDeath; + mUidState = uidState; + mFlags = flags; + + if (mProxy != null) { + proxyPool.release(mProxy); + } + mProxy = proxy; + mAttributionFlags = attributionFlags; + mAttributionChainId = attributionChainId; + + clientId.linkToDeath(this, 0); + } + + /** @return Wall clock time of startOp event */ + public long getStartTime() { + return mStartTime; + } + + /** @return Elapsed time since boot of startOp event */ + public long getStartElapsedTime() { + return mStartElapsedTime; + } + + /** @return Id of the client that started the event */ + public @NonNull IBinder getClientId() { + return mClientId; + } + + /** @return uidstate used when calling startOp */ + public @AppOpsManager.UidState int getUidState() { + return mUidState; + } + + /** @return proxy tag for the access */ + public @Nullable AppOpsManager.OpEventProxyInfo getProxy() { + return mProxy; + } + + /** @return flags used for the access */ + public @AppOpsManager.OpFlags int getFlags() { + return mFlags; + } + + /** @return attributoin flags used for the access */ + public @AppOpsManager.AttributionFlags int getAttributionFlags() { + return mAttributionFlags; + } + + /** @return attribution chain id for the access */ + public int getAttributionChainId() { + return mAttributionChainId; + } + + public void setStartTime(long startTime) { + mStartTime = startTime; + } + + public void setStartElapsedTime(long startElapsedTime) { + mStartElapsedTime = startElapsedTime; + } + } + + /** + * An unsynchronized pool of {@link InProgressStartOpEvent} objects. + */ + static class InProgressStartOpEventPool extends Pools.SimplePool { + private OpEventProxyInfoPool mOpEventProxyInfoPool; + + InProgressStartOpEventPool(OpEventProxyInfoPool opEventProxyInfoPool, + int maxUnusedPooledObjects) { + super(maxUnusedPooledObjects); + this.mOpEventProxyInfoPool = opEventProxyInfoPool; + } + + InProgressStartOpEvent acquire(long startTime, long elapsedTime, @NonNull IBinder clientId, + @Nullable String attributionTag, @NonNull Runnable onDeath, int proxyUid, + @Nullable String proxyPackageName, @Nullable String proxyAttributionTag, + @AppOpsManager.UidState int uidState, @AppOpsManager.OpFlags int flags, + @AppOpsManager.AttributionFlags + int attributionFlags, int attributionChainId) throws RemoteException { + + InProgressStartOpEvent recycled = acquire(); + + AppOpsManager.OpEventProxyInfo proxyInfo = null; + if (proxyUid != Process.INVALID_UID) { + proxyInfo = mOpEventProxyInfoPool.acquire(proxyUid, proxyPackageName, + proxyAttributionTag); + } + + if (recycled != null) { + recycled.reinit(startTime, elapsedTime, clientId, attributionTag, onDeath, + uidState, flags, proxyInfo, attributionFlags, attributionChainId, + mOpEventProxyInfoPool); + return recycled; + } + + return new InProgressStartOpEvent(startTime, elapsedTime, clientId, attributionTag, + onDeath, uidState, proxyInfo, flags, attributionFlags, attributionChainId); + } + } + + /** + * An unsynchronized pool of {@link AppOpsManager.OpEventProxyInfo} objects. + */ + static class OpEventProxyInfoPool extends Pools.SimplePool { + OpEventProxyInfoPool(int maxUnusedPooledObjects) { + super(maxUnusedPooledObjects); + } + + AppOpsManager.OpEventProxyInfo acquire(@IntRange(from = 0) int uid, + @Nullable String packageName, + @Nullable String attributionTag) { + AppOpsManager.OpEventProxyInfo recycled = acquire(); + if (recycled != null) { + recycled.reinit(uid, packageName, attributionTag); + return recycled; + } + + return new AppOpsManager.OpEventProxyInfo(uid, packageName, attributionTag); + } + } }