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

Commit cd6e48ac authored by Treehugger Robot's avatar Treehugger Robot Committed by Android (Google) Code Review
Browse files

Merge "Log when the location indicator switches OFF" into main

parents 0d167fad 6d4014ce
Loading
Loading
Loading
Loading
+1 −1
Original line number Original line Diff line number Diff line
@@ -105,7 +105,7 @@ public class PermissionUsageHelper implements AppOpsManager.OnOpActiveChangedLis
    private static final long DEFAULT_RUNNING_TIME_MS = 5000L;
    private static final long DEFAULT_RUNNING_TIME_MS = 5000L;
    private static final long ADDITIONAL_RUNNING_TIME_LOCATION_ONLY_MS =
    private static final long ADDITIONAL_RUNNING_TIME_LOCATION_ONLY_MS =
            10_000L - DEFAULT_RUNNING_TIME_MS;
            10_000L - DEFAULT_RUNNING_TIME_MS;
    // LINT.ThenChange(/packages/SystemUI/src/com/android/systemui/privacy/PrivacyItemController.kt)
    // LINT.ThenChange(/packages/SystemUI/src/com/android/systemui/privacy/PrivacyItemController.kt, /packages/SystemUI/src/com/android/systemui/appops/AppOpsControllerImpl.java)
    private static final long DEFAULT_RECENT_TIME_MS = 15000L;
    private static final long DEFAULT_RECENT_TIME_MS = 15000L;


    private static boolean shouldShowIndicators() {
    private static boolean shouldShowIndicators() {
+18 −2
Original line number Original line Diff line number Diff line
@@ -26,6 +26,7 @@ import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Context;
import android.content.Intent;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.IntentFilter;
import android.location.flags.Flags;
import android.media.AudioManager;
import android.media.AudioManager;
import android.media.AudioRecordingConfiguration;
import android.media.AudioRecordingConfiguration;
import android.os.Handler;
import android.os.Handler;
@@ -70,10 +71,14 @@ public class AppOpsControllerImpl extends BroadcastReceiver implements AppOpsCon
        AppOpsManager.OnOpNotedInternalListener, IndividualSensorPrivacyController.Callback,
        AppOpsManager.OnOpNotedInternalListener, IndividualSensorPrivacyController.Callback,
        Dumpable {
        Dumpable {


    // LINT.IfChange
    // This is the minimum time that we will keep AppOps that are noted on record. If multiple
    // This is the minimum time that we will keep AppOps that are noted on record. If multiple
    // occurrences of the same (op, package, uid) happen in a shorter interval, they will not be
    // occurrences of the same (op, package, uid) happen in a shorter interval, they will not be
    // notified to listeners.
    // notified to listeners.
    private static final long NOTED_OP_TIME_DELAY_MS = 5000;
    private static final long NOTED_OP_TIME_DELAY_MS = 5000;
    // This is the minimum time that we will keep AppOps that are noted on record for location only.
    private static final long NOTED_OP_TIME_LOCATION_ONLY_DELAY_MS = 10_000;
    // LINT.ThenChange(/packages/SystemUI/src/com/android/systemui/privacy/PrivacyItemController.kt, /core/java/android/permission/PermissionUsageHelper.java)
    private static final String TAG = "AppOpsControllerImpl";
    private static final String TAG = "AppOpsControllerImpl";
    private static final boolean DEBUG = false;
    private static final boolean DEBUG = false;


@@ -255,7 +260,7 @@ public class AppOpsControllerImpl extends BroadcastReceiver implements AppOpsCon
    }
    }


    /**
    /**
     * Adds a callback that will get notifified when an AppOp of the type the controller tracks
     * Adds a callback that will get notified when an AppOp of the type the controller tracks
     * changes
     * changes
     *
     *
     * @param callback Callback to report changes
     * @param callback Callback to report changes
@@ -368,7 +373,11 @@ public class AppOpsControllerImpl extends BroadcastReceiver implements AppOpsCon
        }
        }
        // We should keep this so we make sure it cannot time out.
        // We should keep this so we make sure it cannot time out.
        mBGHandler.removeCallbacksAndMessages(item);
        mBGHandler.removeCallbacksAndMessages(item);
        mBGHandler.scheduleRemoval(item, NOTED_OP_TIME_DELAY_MS);
        final long delay =
                (Flags.locationIndicatorsEnabled() && isOpLocation(code))
                        ? NOTED_OP_TIME_LOCATION_ONLY_DELAY_MS
                        : NOTED_OP_TIME_DELAY_MS;
        mBGHandler.scheduleRemoval(item, delay);
        return createdNew;
        return createdNew;
    }
    }


@@ -626,6 +635,13 @@ public class AppOpsControllerImpl extends BroadcastReceiver implements AppOpsCon
        return false;
        return false;
    }
    }


    private boolean isOpLocation(int op) {
        for (int i = 0; i < OPS_LOC.length; i++) {
            if (op == OPS_LOC[i]) return true;
        }
        return false;
    }

    protected class H extends Handler {
    protected class H extends Handler {
        H(Looper looper) {
        H(Looper looper) {
            super(looper);
            super(looper);
+77 −33
Original line number Original line Diff line number Diff line
@@ -139,14 +139,15 @@ constructor(
                        logger.logUpdatedItemFromAppOps(code, uid, packageName, active)
                        logger.logUpdatedItemFromAppOps(code, uid, packageName, active)


                        val procInfo =
                        val procInfo =
                            (activityManager.runningAppProcesses
                            (activityManager.runningAppProcesses ?: emptyList()).find {
                                ?: emptyList()).find { it.uid == uid }
                                it.uid == uid
                            }
                        val importance = procInfo?.importance ?: -1 // Use -1 if process not found
                        val importance = procInfo?.importance ?: -1 // Use -1 if process not found
                        logger.logLocationAppOps(
                        logger.logLocationAppOps(
                            uid,
                            uid,
                            packageName,
                            packageName,
                            importance,
                            importance,
                            !isBackgroundApp(uid)
                            !isBackgroundApp(uid),
                        )
                        )


                        dispatchOnPrivacyItemsChanged()
                        dispatchOnPrivacyItemsChanged()
@@ -290,35 +291,48 @@ constructor(
    private fun logLocationAccesses() {
    private fun logLocationAccesses() {
        // TODO(b/419834493): Add logbuffer logging here for bugreport debugging.
        // TODO(b/419834493): Add logbuffer logging here for bugreport debugging.
        synchronized(lock) {
        synchronized(lock) {
            if (!lastHighPowerLocationOp && hasHighPowerLocationAccess) {
            logLocationIndicatorEvent(
                uiEventLogger.log {
                lastState = lastHighPowerLocationOp,
                    LocationIndicatorEvent.LOCATION_INDICATOR_MONITOR_HIGH_POWER.id
                currentState = hasHighPowerLocationAccess,
                }
                onEvent = LocationIndicatorEvent.LOCATION_INDICATOR_MONITOR_HIGH_POWER,
            }
                offEvent = LocationIndicatorEvent.LOCATION_INDICATOR_MONITOR_HIGH_POWER_OFF,
            if (!lastLocationIndicator && hasNonSystemForegroundLocationAccess) {
            )
                uiEventLogger.log { LocationIndicatorEvent.LOCATION_INDICATOR_NON_SYSTEM_APP.id }
            logLocationIndicatorEvent(
            }
                lastState = lastLocationIndicator,
            if (!lastLocationIndicatorWithSystem) {
                currentState = hasNonSystemForegroundLocationAccess,
                if (hasNonSystemForegroundLocationAccess || hasSystemLocationAccess) {
                onEvent = LocationIndicatorEvent.LOCATION_INDICATOR_NON_SYSTEM_APP,
                    uiEventLogger.log { LocationIndicatorEvent.LOCATION_INDICATOR_SYSTEM_APP.id }
                offEvent = LocationIndicatorEvent.LOCATION_INDICATOR_NON_SYSTEM_APP_OFF,
                }
            )
            }

            if (!lastLocationIndicatorWithBackround) {
            // No background access
                if (hasNonSystemForegroundLocationAccess || hasBackgroundLocationAccess) {
            val hasSystemAccess = hasNonSystemForegroundLocationAccess || hasSystemLocationAccess
                    uiEventLogger.log {
            logLocationIndicatorEvent(
                        LocationIndicatorEvent.LOCATION_INDICATOR_BACKGROUND_APP.id
                lastState = lastLocationIndicatorWithSystem,
                    }
                currentState = hasSystemAccess,
                }
                onEvent = LocationIndicatorEvent.LOCATION_INDICATOR_SYSTEM_APP,
            }
                offEvent = LocationIndicatorEvent.LOCATION_INDICATOR_SYSTEM_APP_OFF,
            if (!lastLocationIndicatorWithSystemAndBackround) {
            )
                if (

            // No system access
            val hasBackgroundAccess =
                hasNonSystemForegroundLocationAccess || hasBackgroundLocationAccess
            logLocationIndicatorEvent(
                lastState = lastLocationIndicatorWithBackround,
                currentState = hasBackgroundAccess,
                onEvent = LocationIndicatorEvent.LOCATION_INDICATOR_BACKGROUND_APP,
                offEvent = LocationIndicatorEvent.LOCATION_INDICATOR_BACKGROUND_APP_OFF,
            )

            val hasAllAccess =
                hasNonSystemForegroundLocationAccess ||
                hasNonSystemForegroundLocationAccess ||
                    hasSystemLocationAccess ||
                    hasSystemLocationAccess ||
                    hasBackgroundLocationAccess
                    hasBackgroundLocationAccess
                ) {
            logLocationIndicatorEvent(
                    uiEventLogger.log { LocationIndicatorEvent.LOCATION_INDICATOR_ALL_APP.id }
                lastLocationIndicatorWithSystemAndBackround,
                }
                hasAllAccess,
            }
                LocationIndicatorEvent.LOCATION_INDICATOR_ALL_APP,
                LocationIndicatorEvent.LOCATION_INDICATOR_ALL_APP_OFF,
            )


            hasHighPowerLocationAccess = false
            hasHighPowerLocationAccess = false
            hasSystemLocationAccess = false
            hasSystemLocationAccess = false
@@ -327,6 +341,17 @@ constructor(
        }
        }
    }
    }


    private fun logLocationIndicatorEvent(
        lastState: Boolean,
        currentState: Boolean,
        onEvent: LocationIndicatorEvent,
        offEvent: LocationIndicatorEvent,
    ) {
        if (lastState != currentState) {
            uiEventLogger.log(if (currentState) onEvent else offEvent)
        }
    }

    @GuardedBy("lock")
    @GuardedBy("lock")
    private fun privacyItemForAppOpEnabledLocked(code: Int): Boolean {
    private fun privacyItemForAppOpEnabledLocked(code: Int): Boolean {
        if (code in OPS_LOCATION) {
        if (code in OPS_LOCATION) {
@@ -486,24 +511,43 @@ constructor(
        // Copied from LocationControllerImpl.java
        // Copied from LocationControllerImpl.java
        @UiEvent(doc = "Location indicator shown for high power access")
        @UiEvent(doc = "Location indicator shown for high power access")
        LOCATION_INDICATOR_MONITOR_HIGH_POWER(935),
        LOCATION_INDICATOR_MONITOR_HIGH_POWER(935),
        @UiEvent(doc = "Location indicator hidden for high power access")
        LOCATION_INDICATOR_MONITOR_HIGH_POWER_OFF(2417),
        // Copied from LocationControllerImpl.java
        // Copied from LocationControllerImpl.java
        @UiEvent(
        @UiEvent(
            doc =
            doc =
                "Location indicator shown for system, non-system, foreground app access (i.e., excluding background)"
                "Location indicator shown for system, non-system, foreground app access (i.e., excluding background)"
        )
        )
        LOCATION_INDICATOR_SYSTEM_APP(936),
        LOCATION_INDICATOR_SYSTEM_APP(936),
        @UiEvent(
            doc =
                "Location indicator hidden for system, non-system, foreground app access (i.e., excluding background)"
        )
        LOCATION_INDICATOR_SYSTEM_APP_OFF(2418),
        // Copied from LocationControllerImpl.java
        // Copied from LocationControllerImpl.java
        @UiEvent(
        @UiEvent(
            doc =
            doc =
                "Location indicator shown for non-system, foreground app access (i.e., excluding system and background)"
                "Location indicator shown for non-system, foreground app access (i.e., excluding system and background)"
        )
        )
        LOCATION_INDICATOR_NON_SYSTEM_APP(937),
        LOCATION_INDICATOR_NON_SYSTEM_APP(937),
        @UiEvent(
            doc =
                "Location indicator hidden for non-system, foreground app access (i.e., excluding system and background)"
        )
        LOCATION_INDICATOR_NON_SYSTEM_APP_OFF(2419),
        @UiEvent(
        @UiEvent(
            doc =
            doc =
                "Location indicator shown for non-system, foreground, background app access (i.e., excluding system)"
                "Location indicator shown for non-system, foreground, background app access (i.e., excluding system)"
        )
        )
        LOCATION_INDICATOR_BACKGROUND_APP(2325),
        LOCATION_INDICATOR_BACKGROUND_APP(2325),
        @UiEvent(doc = "Location indicator shown for all access") LOCATION_INDICATOR_ALL_APP(2354);
        @UiEvent(
            doc =
                "Location indicator hidden for non-system, foreground, background app access (i.e., excluding system)"
        )
        LOCATION_INDICATOR_BACKGROUND_APP_OFF(2420),
        @UiEvent(doc = "Location indicator shown for all access") LOCATION_INDICATOR_ALL_APP(2354),
        @UiEvent(doc = "Location indicator hidden for all access")
        LOCATION_INDICATOR_ALL_APP_OFF(2421);


        override fun getId(): Int {
        override fun getId(): Int {
            return id
            return id
+1 −1
Original line number Original line Diff line number Diff line
@@ -51,7 +51,7 @@ class PrivacyItemController @Inject constructor(
        // LINT.IfChange
        // LINT.IfChange
        @VisibleForTesting const val TIME_TO_HOLD_INDICATORS = 5_000L
        @VisibleForTesting const val TIME_TO_HOLD_INDICATORS = 5_000L
        @VisibleForTesting const val TIME_TO_HOLD_INDICATORS_FOR_LOCATION = 10_000L
        @VisibleForTesting const val TIME_TO_HOLD_INDICATORS_FOR_LOCATION = 10_000L
        // LINT.ThenChange(/core/java/android/permission/PermissionUsageHelper.java)
        // LINT.ThenChange(/core/java/android/permission/PermissionUsageHelper.java, /packages/SystemUI/src/com/android/systemui/appops/AppOpsControllerImpl.java)
    }
    }


    @VisibleForTesting
    @VisibleForTesting
+32 −0
Original line number Original line Diff line number Diff line
@@ -46,10 +46,12 @@ import static org.mockito.Mockito.when;
import android.app.AppOpsManager;
import android.app.AppOpsManager;
import android.content.Context;
import android.content.Context;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager;
import android.location.flags.Flags;
import android.media.AudioManager;
import android.media.AudioManager;
import android.media.AudioRecordingConfiguration;
import android.media.AudioRecordingConfiguration;
import android.os.Looper;
import android.os.Looper;
import android.os.UserHandle;
import android.os.UserHandle;
import android.platform.test.annotations.EnableFlags;
import android.testing.TestableLooper;
import android.testing.TestableLooper;


import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.ext.junit.runners.AndroidJUnit4;
@@ -66,6 +68,7 @@ import com.android.systemui.util.time.FakeSystemClock;
import org.junit.Before;
import org.junit.Before;
import org.junit.Test;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
import org.mockito.InOrder;
import org.mockito.InOrder;
import org.mockito.Mock;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.mockito.MockitoAnnotations;
@@ -539,6 +542,35 @@ public class AppOpsControllerTest extends SysuiTestCase {
        verify(mMockHandler).scheduleRemoval(any(AppOpItem.class), anyLong());
        verify(mMockHandler).scheduleRemoval(any(AppOpItem.class), anyLong());
    }
    }


    @Test
    @EnableFlags(Flags.FLAG_LOCATION_INDICATORS_ENABLED)
    public void opNotedScheduledForRemoval_delayIsCorrect() {
        mController.setBGHandler(mMockHandler);
        ArgumentCaptor<AppOpItem> itemCaptor = ArgumentCaptor.forClass(AppOpItem.class);
        ArgumentCaptor<Long> delayCaptor = ArgumentCaptor.forClass(Long.class);

        // Location op is noted
        mController.onOpNoted(AppOpsManager.OP_FINE_LOCATION, TEST_UID, TEST_PACKAGE_NAME,
                TEST_ATTRIBUTION_NAME, AppOpsManager.OP_FLAG_SELF, AppOpsManager.MODE_ALLOWED);

        // Non-location op is noted
        mController.onOpNoted(AppOpsManager.OP_RECORD_AUDIO, TEST_UID, TEST_PACKAGE_NAME,
                TEST_ATTRIBUTION_NAME, AppOpsManager.OP_FLAG_SELF, AppOpsManager.MODE_ALLOWED);

        // Check they are both scheduled for removal with the correct delays
        verify(mMockHandler, times(2)).scheduleRemoval(itemCaptor.capture(),
                delayCaptor.capture());

        List<AppOpItem> items = itemCaptor.getAllValues();
        List<Long> delays = delayCaptor.getAllValues();

        assertEquals(AppOpsManager.OP_FINE_LOCATION, items.get(0).getCode());
        assertEquals(10000L, delays.get(0).longValue());

        assertEquals(AppOpsManager.OP_RECORD_AUDIO, items.get(1).getCode());
        assertEquals(5000L, delays.get(1).longValue());
    }

    @Test
    @Test
    public void noItemsAfterStopListening() {
    public void noItemsAfterStopListening() {
        mController.setBGHandler(mMockHandler);
        mController.setBGHandler(mMockHandler);
Loading