Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit dcff4e80 authored by Yuting Fang's avatar Yuting Fang Committed by Android (Google) Code Review
Browse files

Merge "Log AppOp access events in DiscreteRegistry" into main

parents 27ee47bc a60bd295
Loading
Loading
Loading
Loading
+8 −0
Original line number Diff line number Diff line
@@ -257,3 +257,11 @@ flag {
    description: "This flag is used to enable replacing permission BODY_SENSORS(and BODY_SENSORS_BACKGROUND) with granular health permission READ_HEART_RATE(and READ_HEALTH_DATA_IN_BACKGROUND)"
    bug: "364638912"
}

flag {
    name: "appop_access_tracking_logging_enabled"
    is_fixed_read_only: true
    namespace: "permissions"
    description: "Enables logging of the AppOp access tracking"
    bug: "365584286"
}
+22 −14
Original line number Diff line number Diff line
@@ -110,7 +110,8 @@ final class AttributedOp {

        mAppOpsService.mHistoricalRegistry.incrementOpAccessedCount(parent.op, parent.uid,
                parent.packageName, persistentDeviceId, tag, uidState, flags, accessTime,
                AppOpsManager.ATTRIBUTION_FLAGS_NONE, AppOpsManager.ATTRIBUTION_CHAIN_ID_NONE);
                AppOpsManager.ATTRIBUTION_FLAGS_NONE, AppOpsManager.ATTRIBUTION_CHAIN_ID_NONE,
                DiscreteRegistry.ACCESS_TYPE_NOTE_OP);
    }

    /**
@@ -254,7 +255,7 @@ final class AttributedOp {
        if (isStarted) {
            mAppOpsService.mHistoricalRegistry.incrementOpAccessedCount(parent.op, parent.uid,
                    parent.packageName, persistentDeviceId, tag, uidState, flags, startTime,
                    attributionFlags, attributionChainId);
                    attributionFlags, attributionChainId, DiscreteRegistry.ACCESS_TYPE_START_OP);
        }
    }

@@ -290,11 +291,16 @@ final class AttributedOp {
     * stopping in the HistoricalRegistry, but does not delete it.
     *
     * @param triggeredByUidStateChange If {@code true}, then this method operates as usual, except
     * that {@link AppOpsService#mActiveWatchers} will not be notified. This is currently only
     * used in {@link #onUidStateChanged(int)}, for the purpose of restarting (i.e.,
     * finishing then immediately starting again in the new uid state) the AttributedOp. In this
     * case, the caller is responsible for guaranteeing that either the AttributedOp is started
     * again or all {@link AppOpsService#mActiveWatchers} are notified that the AttributedOp is
     *                                  that {@link AppOpsService#mActiveWatchers} will not be
     *                                  notified. This is currently only
     *                                  used in {@link #onUidStateChanged(int)}, for the purpose of
     *                                  restarting (i.e.,
     *                                  finishing then immediately starting again in the new uid
     *                                  state) the AttributedOp. In this
     *                                  case, the caller is responsible for guaranteeing that either
     *                                  the AttributedOp is started
     *                                  again or all {@link AppOpsService#mActiveWatchers} are
     *                                  notified that the AttributedOp is
     *                                  finished.
     */
    @SuppressWarnings("GuardedBy") // Lock is held on mAppOpsService
@@ -335,7 +341,9 @@ final class AttributedOp {
            mAppOpsService.mHistoricalRegistry.increaseOpAccessDuration(parent.op, parent.uid,
                    parent.packageName, persistentDeviceId, tag, event.getUidState(),
                    event.getFlags(), finishedEvent.getNoteTime(), finishedEvent.getDuration(),
                    event.getAttributionFlags(), event.getAttributionChainId());
                    event.getAttributionFlags(), event.getAttributionChainId(),
                    isPausing ? DiscreteRegistry.ACCESS_TYPE_PAUSE_OP
                            : DiscreteRegistry.ACCESS_TYPE_FINISH_OP);

            if (!isPausing) {
                mAppOpsService.mInProgressStartOpEventPool.release(event);
@@ -443,7 +451,7 @@ final class AttributedOp {
            mAppOpsService.mHistoricalRegistry.incrementOpAccessedCount(parent.op, parent.uid,
                    parent.packageName, persistentDeviceId, tag, event.getUidState(),
                    event.getFlags(), startTime, event.getAttributionFlags(),
                    event.getAttributionChainId());
                    event.getAttributionChainId(), DiscreteRegistry.ACCESS_TYPE_RESUME_OP);
            if (shouldSendActive) {
                mAppOpsService.scheduleOpActiveChangedIfNeededLocked(parent.op, parent.uid,
                        parent.packageName, tag, event.getVirtualDeviceId(), true,
@@ -867,9 +875,9 @@ final class AttributedOp {
                @Nullable String attributionTag, int virtualDeviceId, @NonNull Runnable onDeath,
                int proxyUid, @Nullable String proxyPackageName,
                @Nullable String proxyAttributionTag, @Nullable String proxyDeviceId,
                @AppOpsManager.UidState int uidState,
                @AppOpsManager.OpFlags int flags, @AppOpsManager.AttributionFlags
                int attributionFlags, int attributionChainId) throws RemoteException {
                @AppOpsManager.UidState int uidState, @AppOpsManager.OpFlags int flags,
                @AppOpsManager.AttributionFlags int attributionFlags, int attributionChainId)
                throws RemoteException {

            InProgressStartOpEvent recycled = acquire();

+67 −4
Original line number Diff line number Diff line
@@ -32,13 +32,23 @@ import static android.app.AppOpsManager.OP_FLAGS_ALL;
import static android.app.AppOpsManager.OP_FLAG_SELF;
import static android.app.AppOpsManager.OP_FLAG_TRUSTED_PROXIED;
import static android.app.AppOpsManager.OP_FLAG_TRUSTED_PROXY;
import static android.app.AppOpsManager.OP_MONITOR_HIGH_POWER_LOCATION;
import static android.app.AppOpsManager.OP_MONITOR_LOCATION;
import static android.app.AppOpsManager.OP_NONE;
import static android.app.AppOpsManager.OP_PHONE_CALL_CAMERA;
import static android.app.AppOpsManager.OP_PHONE_CALL_MICROPHONE;
import static android.app.AppOpsManager.OP_PROCESS_OUTGOING_CALLS;
import static android.app.AppOpsManager.OP_READ_ICC_SMS;
import static android.app.AppOpsManager.OP_READ_SMS;
import static android.app.AppOpsManager.OP_RECEIVE_AMBIENT_TRIGGER_AUDIO;
import static android.app.AppOpsManager.OP_RECEIVE_SANDBOX_TRIGGER_AUDIO;
import static android.app.AppOpsManager.OP_RECORD_AUDIO;
import static android.app.AppOpsManager.OP_RESERVED_FOR_TESTING;
import static android.app.AppOpsManager.OP_SEND_SMS;
import static android.app.AppOpsManager.OP_SMS_FINANCIAL_TRANSACTIONS;
import static android.app.AppOpsManager.OP_SYSTEM_ALERT_WINDOW;
import static android.app.AppOpsManager.OP_WRITE_ICC_SMS;
import static android.app.AppOpsManager.OP_WRITE_SMS;
import static android.app.AppOpsManager.flagsToString;
import static android.app.AppOpsManager.getUidStateName;
import static android.companion.virtual.VirtualDeviceManager.PERSISTENT_DEVICE_ID_DEFAULT;
@@ -46,6 +56,7 @@ import static android.companion.virtual.VirtualDeviceManager.PERSISTENT_DEVICE_I
import static java.lang.Long.min;
import static java.lang.Math.max;

import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.AppOpsManager;
@@ -62,6 +73,7 @@ import android.util.Xml;

import com.android.internal.annotations.GuardedBy;
import com.android.internal.util.ArrayUtils;
import com.android.internal.util.FrameworkStatsLog;
import com.android.internal.util.XmlUtils;
import com.android.modules.utils.TypedXmlPullParser;
import com.android.modules.utils.TypedXmlSerializer;
@@ -72,6 +84,8 @@ import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.PrintWriter;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.text.SimpleDateFormat;
import java.time.Duration;
import java.time.Instant;
@@ -125,7 +139,6 @@ import java.util.Set;
 * relies on {@link HistoricalRegistry} for controlling that no calls are allowed until then. All
 * outside calls are going through {@link HistoricalRegistry}, where
 * {@link HistoricalRegistry#isPersistenceInitializedMLocked()} check is done.
 *
 */

final class DiscreteRegistry {
@@ -142,11 +155,40 @@ final class DiscreteRegistry {
            + OP_PHONE_CALL_MICROPHONE + "," + OP_PHONE_CALL_CAMERA + ","
            + OP_RECEIVE_AMBIENT_TRIGGER_AUDIO + "," + OP_RECEIVE_SANDBOX_TRIGGER_AUDIO
            + "," + OP_RESERVED_FOR_TESTING;
    private static final int[] sDiscreteOpsToLog =
            new int[]{OP_FINE_LOCATION, OP_COARSE_LOCATION, OP_EMERGENCY_LOCATION, OP_CAMERA,
                    OP_RECORD_AUDIO, OP_PHONE_CALL_MICROPHONE, OP_PHONE_CALL_CAMERA,
                    OP_RECEIVE_AMBIENT_TRIGGER_AUDIO, OP_RECEIVE_SANDBOX_TRIGGER_AUDIO, OP_READ_SMS,
                    OP_WRITE_SMS, OP_SEND_SMS, OP_READ_ICC_SMS, OP_WRITE_ICC_SMS,
                    OP_SMS_FINANCIAL_TRANSACTIONS, OP_SYSTEM_ALERT_WINDOW, OP_MONITOR_LOCATION,
                    OP_MONITOR_HIGH_POWER_LOCATION, OP_PROCESS_OUTGOING_CALLS,
            };
    private static final long DEFAULT_DISCRETE_HISTORY_CUTOFF = Duration.ofDays(7).toMillis();
    private static final long MAXIMUM_DISCRETE_HISTORY_CUTOFF = Duration.ofDays(30).toMillis();
    private static final long DEFAULT_DISCRETE_HISTORY_QUANTIZATION =
            Duration.ofMinutes(1).toMillis();

    static final int ACCESS_TYPE_NOTE_OP =
            FrameworkStatsLog.APP_OP_ACCESS_TRACKED__ACCESS_TYPE__NOTE_OP;
    static final int ACCESS_TYPE_START_OP =
            FrameworkStatsLog.APP_OP_ACCESS_TRACKED__ACCESS_TYPE__START_OP;
    static final int ACCESS_TYPE_FINISH_OP =
            FrameworkStatsLog.APP_OP_ACCESS_TRACKED__ACCESS_TYPE__FINISH_OP;
    static final int ACCESS_TYPE_PAUSE_OP =
            FrameworkStatsLog.APP_OP_ACCESS_TRACKED__ACCESS_TYPE__PAUSE_OP;
    static final int ACCESS_TYPE_RESUME_OP =
            FrameworkStatsLog.APP_OP_ACCESS_TRACKED__ACCESS_TYPE__RESUME_OP;

    @Retention(RetentionPolicy.SOURCE)
    @IntDef(prefix = {"ACCESS_TYPE_"}, value = {
            ACCESS_TYPE_NOTE_OP,
            ACCESS_TYPE_START_OP,
            ACCESS_TYPE_FINISH_OP,
            ACCESS_TYPE_PAUSE_OP,
            ACCESS_TYPE_RESUME_OP
    })
    public @interface AccessType {}

    private static long sDiscreteHistoryCutoff;
    private static long sDiscreteHistoryQuantization;
    private static int[] sDiscreteOps;
@@ -255,7 +297,23 @@ final class DiscreteRegistry {
    void recordDiscreteAccess(int uid, String packageName, @NonNull String deviceId, int op,
            @Nullable String attributionTag, @AppOpsManager.OpFlags int flags,
            @AppOpsManager.UidState int uidState, long accessTime, long accessDuration,
            @AppOpsManager.AttributionFlags int attributionFlags, int attributionChainId) {
            @AppOpsManager.AttributionFlags int attributionFlags, int attributionChainId,
            @AccessType int accessType) {
        if (shouldLogAccess(op)) {
            int firstChar = 0;
            if (attributionTag != null && attributionTag.startsWith(packageName)) {
                firstChar = packageName.length();
                if (firstChar < attributionTag.length() && attributionTag.charAt(firstChar)
                        == '.') {
                    firstChar++;
                }
            }
            FrameworkStatsLog.write(FrameworkStatsLog.APP_OP_ACCESS_TRACKED, uid, op, accessType,
                    uidState, flags, attributionFlags,
                    attributionTag == null ? null : attributionTag.substring(firstChar),
                    attributionChainId);
        }

        if (!isDiscreteOp(op, flags)) {
            return;
        }
@@ -1523,6 +1581,11 @@ final class DiscreteRegistry {
        return true;
    }

    private static boolean shouldLogAccess(int op) {
        return Flags.appopAccessTrackingLoggingEnabled()
                && ArrayUtils.contains(sDiscreteOpsToLog, op);
    }

    private static long discretizeTimeStamp(long timeStamp) {
        return timeStamp / sDiscreteHistoryQuantization * sDiscreteHistoryQuantization;

+6 −4
Original line number Diff line number Diff line
@@ -474,7 +474,8 @@ final class HistoricalRegistry {
    void incrementOpAccessedCount(int op, int uid, @NonNull String packageName,
            @NonNull String deviceId, @Nullable String attributionTag, @UidState int uidState,
            @OpFlags int flags, long accessTime,
            @AppOpsManager.AttributionFlags int attributionFlags, int attributionChainId) {
            @AppOpsManager.AttributionFlags int attributionFlags, int attributionChainId,
            @DiscreteRegistry.AccessType int accessType) {
        synchronized (mInMemoryLock) {
            if (mMode == AppOpsManager.HISTORICAL_MODE_ENABLED_ACTIVE) {
                if (!isPersistenceInitializedMLocked()) {
@@ -487,7 +488,7 @@ final class HistoricalRegistry {

                mDiscreteRegistry.recordDiscreteAccess(uid, packageName, deviceId, op,
                        attributionTag, flags, uidState, accessTime, -1, attributionFlags,
                        attributionChainId);
                        attributionChainId, accessType);
            }
        }
    }
@@ -510,7 +511,8 @@ final class HistoricalRegistry {
    void increaseOpAccessDuration(int op, int uid, @NonNull String packageName,
            @NonNull String deviceId, @Nullable String attributionTag, @UidState int uidState,
            @OpFlags int flags, long eventStartTime, long increment,
            @AppOpsManager.AttributionFlags int attributionFlags, int attributionChainId) {
            @AppOpsManager.AttributionFlags int attributionFlags, int attributionChainId,
            @DiscreteRegistry.AccessType int accessType) {
        synchronized (mInMemoryLock) {
            if (mMode == AppOpsManager.HISTORICAL_MODE_ENABLED_ACTIVE) {
                if (!isPersistenceInitializedMLocked()) {
@@ -522,7 +524,7 @@ final class HistoricalRegistry {
                        attributionTag, uidState, flags, increment);
                mDiscreteRegistry.recordDiscreteAccess(uid, packageName, deviceId, op,
                        attributionTag, flags, uidState, eventStartTime, increment,
                        attributionFlags, attributionChainId);
                        attributionFlags, attributionChainId, accessType);
            }
        }
    }
+4 −2
Original line number Diff line number Diff line
@@ -86,7 +86,8 @@ public class DiscreteAppOpPersistenceTest {
        int attributionChainId = AppOpsManager.ATTRIBUTION_CHAIN_ID_NONE;

        mDiscreteRegistry.recordDiscreteAccess(uid, packageName, deviceId, op, null, opFlags,
                uidState, accessTime, duration, attributionFlags, attributionChainId);
                uidState, accessTime, duration, attributionFlags, attributionChainId,
                DiscreteRegistry.ACCESS_TYPE_FINISH_OP);

        // Verify in-memory object is correct
        fetchDiscreteOpsAndValidate(uid, packageName, op, deviceId, null, accessTime,
@@ -117,7 +118,8 @@ public class DiscreteAppOpPersistenceTest {
        int attributionChainId = 10;

        mDiscreteRegistry.recordDiscreteAccess(uid, packageName, deviceId, op, null, opFlags,
                uidState, accessTime, duration, attributionFlags, attributionChainId);
                uidState, accessTime, duration, attributionFlags, attributionChainId,
                DiscreteRegistry.ACCESS_TYPE_START_OP);

        fetchDiscreteOpsAndValidate(uid, packageName, op, deviceId, null, accessTime,
                duration, uidState, opFlags, attributionFlags, attributionChainId);