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

Commit e1f886f5 authored by David Christie's avatar David Christie Committed by Android (Google) Code Review
Browse files

Merge "Add new app op to monitor high power location requests."

parents 1a02c22d 0b837450
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -3164,6 +3164,7 @@ package android.app {
    field public static final int OP_COARSE_LOCATION = 0; // 0x0
    field public static final int OP_FINE_LOCATION = 1; // 0x1
    field public static final int OP_GPS = 2; // 0x2
    field public static final int OP_MONITOR_HIGH_POWER_LOCATION = 42; // 0x2a
    field public static final int OP_MONITOR_LOCATION = 41; // 0x29
    field public static final int OP_NONE = -1; // 0xffffffff
  }
+8 −2
Original line number Diff line number Diff line
@@ -67,6 +67,7 @@ public class AppOpsManager {
    //  - increment _NUM_OP
    //  - add rows to sOpToSwitch, sOpNames, sOpPerms
    //  - add descriptive strings to Settings/res/values/arrays.xml
    //  - add the op to the appropriate template in AppOpsState.OpsTemplate (settings app)

    /** No operation specified. */
    public static final int OP_NONE = -1;
@@ -154,15 +155,17 @@ public class AppOpsManager {
    public static final int OP_WAKE_LOCK = 40;
    /** Continually monitoring location data. */
    public static final int OP_MONITOR_LOCATION = 41;
    /** Continually monitoring location data with a relatively high power request. */
    public static final int OP_MONITOR_HIGH_POWER_LOCATION = 42;
    /** @hide */
    public static final int _NUM_OP = 42;
    public static final int _NUM_OP = 43;

    /**
     * This maps each operation to the operation that serves as the
     * switch to determine whether it is allowed.  Generally this is
     * a 1:1 mapping, but for some things (like location) that have
     * multiple low-level operations being tracked that should be
     * presented to hte user as one switch then this can be used to
     * presented to the user as one switch then this can be used to
     * make them all controlled by the same single operation.
     */
    private static int[] sOpToSwitch = new int[] {
@@ -208,6 +211,7 @@ public class AppOpsManager {
            OP_AUDIO_BLUETOOTH_VOLUME,
            OP_WAKE_LOCK,
            OP_COARSE_LOCATION,
            OP_COARSE_LOCATION,
    };

    /**
@@ -257,6 +261,7 @@ public class AppOpsManager {
            "AUDIO_BLUETOOTH_VOLUME",
            "WAKE_LOCK",
            "MONITOR_LOCATION",
            "MONITOR_HIGH_POWER_LOCATION",
    };

    /**
@@ -306,6 +311,7 @@ public class AppOpsManager {
            null, // no permission for changing bluetooth volume
            android.Manifest.permission.WAKE_LOCK,
            null, // no permission for generic location monitoring
            null, // no permission for high power location monitoring
    };

    /**
+47 −8
Original line number Diff line number Diff line
@@ -117,6 +117,9 @@ public class LocationManagerService extends ILocationManager.Stub {

    private static final long NANOS_PER_MILLI = 1000000L;

    // The maximum interval a location request can have and still be considered "high power".
    private static final long HIGH_POWER_INTERVAL_MS = 5 * 60 * 1000;

    // Location Providers may sometimes deliver location updates
    // slightly faster that requested - provide grace period so
    // we don't unnecessarily filter events that are otherwise on
@@ -463,7 +466,10 @@ public class LocationManagerService extends ILocationManager.Stub {

        final HashMap<String,UpdateRecord> mUpdateRecords = new HashMap<String,UpdateRecord>();

        // True if app ops has started monitoring this receiver for locations.
        boolean mOpMonitoring;
        // True if app ops has started monitoring this receiver for high power (gps) locations.
        boolean mOpHighPowerMonitoring;
        int mPendingBroadcasts;
        PowerManager.WakeLock mWakeLock;

@@ -526,18 +532,48 @@ public class LocationManagerService extends ILocationManager.Stub {
        }

        public void updateMonitoring(boolean allow) {
            if (!mOpMonitoring) {
                if (allow) {
                    mOpMonitoring = mAppOps.startOpNoThrow(AppOpsManager.OP_MONITOR_LOCATION,
                            mUid, mPackageName) == AppOpsManager.MODE_ALLOWED;
            // First update monitoring of any location request (including high power).
            mOpMonitoring = updateMonitoring(allow, mOpMonitoring,
                    AppOpsManager.OP_MONITOR_LOCATION);

            // Now update monitoring of high power requests only.
            // A high power request is any gps request with interval under a threshold.
            boolean allowHighPower = allow;
            if (allowHighPower) {
                UpdateRecord gpsRecord = mUpdateRecords.get(LocationManager.GPS_PROVIDER);
                if (gpsRecord == null
                        || gpsRecord.mRequest.getInterval() > HIGH_POWER_INTERVAL_MS) {
                    allowHighPower = false;
                }
            }
            mOpHighPowerMonitoring = updateMonitoring(allowHighPower, mOpHighPowerMonitoring,
                    AppOpsManager.OP_MONITOR_HIGH_POWER_LOCATION);
        }

        /**
         * Update AppOps monitoring for a single location request and op type.
         *
         * @param allowMonitoring True if monitoring is allowed for this request/op.
         * @param currentlyMonitoring True if AppOps is currently monitoring this request/op.
         * @param op AppOps code for the op to update.
         * @return True if monitoring is on for this request/op after updating.
         */
        private boolean updateMonitoring(boolean allowMonitoring, boolean currentlyMonitoring,
                int op) {
            if (!currentlyMonitoring) {
                if (allowMonitoring) {
                    return mAppOps.startOpNoThrow(op, mUid, mPackageName)
                            == AppOpsManager.MODE_ALLOWED;
                }
            } else {
                if (!allow || mAppOps.checkOpNoThrow(AppOpsManager.OP_MONITOR_LOCATION,
                        mUid, mPackageName) != AppOpsManager.MODE_ALLOWED) {
                    mAppOps.finishOp(AppOpsManager.OP_MONITOR_LOCATION, mUid, mPackageName);
                    mOpMonitoring = false;
                if (!allowMonitoring || mAppOps.checkOpNoThrow(op, mUid, mPackageName)
                        != AppOpsManager.MODE_ALLOWED) {
                    mAppOps.finishOp(op, mUid, mPackageName);
                    return false;
                }
            }

            return currentlyMonitoring;
        }

        public boolean isListener() {
@@ -1383,6 +1419,9 @@ public class LocationManagerService extends ILocationManager.Stub {
            // Notify the listener that updates are currently disabled
            receiver.callProviderEnabledLocked(name, false);
        }
        // Update the monitoring here just in case multiple location requests were added to the
        // same receiver (this request may be high power and the initial might not have been).
        receiver.updateMonitoring(true);
    }

    @Override