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

    // LINT.IfChange
    // 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
    // notified to listeners.
    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 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
     *
     * @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.
        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;
    }

@@ -626,6 +635,13 @@ public class AppOpsControllerImpl extends BroadcastReceiver implements AppOpsCon
        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 {
        H(Looper looper) {
            super(looper);
+77 −33
Original line number Diff line number Diff line
@@ -139,14 +139,15 @@ constructor(
                        logger.logUpdatedItemFromAppOps(code, uid, packageName, active)

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

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

            // No background access
            val hasSystemAccess = hasNonSystemForegroundLocationAccess || hasSystemLocationAccess
            logLocationIndicatorEvent(
                lastState = lastLocationIndicatorWithSystem,
                currentState = hasSystemAccess,
                onEvent = LocationIndicatorEvent.LOCATION_INDICATOR_SYSTEM_APP,
                offEvent = LocationIndicatorEvent.LOCATION_INDICATOR_SYSTEM_APP_OFF,
            )

            // 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 ||
                    hasSystemLocationAccess ||
                    hasBackgroundLocationAccess
                ) {
                    uiEventLogger.log { LocationIndicatorEvent.LOCATION_INDICATOR_ALL_APP.id }
                }
            }
            logLocationIndicatorEvent(
                lastLocationIndicatorWithSystemAndBackround,
                hasAllAccess,
                LocationIndicatorEvent.LOCATION_INDICATOR_ALL_APP,
                LocationIndicatorEvent.LOCATION_INDICATOR_ALL_APP_OFF,
            )

            hasHighPowerLocationAccess = 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")
    private fun privacyItemForAppOpEnabledLocked(code: Int): Boolean {
        if (code in OPS_LOCATION) {
@@ -486,24 +511,43 @@ constructor(
        // Copied from LocationControllerImpl.java
        @UiEvent(doc = "Location indicator shown for high power access")
        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
        @UiEvent(
            doc =
                "Location indicator shown for system, non-system, foreground app access (i.e., excluding background)"
        )
        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
        @UiEvent(
            doc =
                "Location indicator shown for non-system, foreground app access (i.e., excluding system and background)"
        )
        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(
            doc =
                "Location indicator shown for non-system, foreground, background app access (i.e., excluding system)"
        )
        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 {
            return id
+1 −1
Original line number Diff line number Diff line
@@ -51,7 +51,7 @@ class PrivacyItemController @Inject constructor(
        // LINT.IfChange
        @VisibleForTesting const val TIME_TO_HOLD_INDICATORS = 5_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
+32 −0
Original line number Diff line number Diff line
@@ -46,10 +46,12 @@ import static org.mockito.Mockito.when;
import android.app.AppOpsManager;
import android.content.Context;
import android.content.pm.PackageManager;
import android.location.flags.Flags;
import android.media.AudioManager;
import android.media.AudioRecordingConfiguration;
import android.os.Looper;
import android.os.UserHandle;
import android.platform.test.annotations.EnableFlags;
import android.testing.TestableLooper;

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.Test;
import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
import org.mockito.InOrder;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
@@ -539,6 +542,35 @@ public class AppOpsControllerTest extends SysuiTestCase {
        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
    public void noItemsAfterStopListening() {
        mController.setBGHandler(mMockHandler);
Loading