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

Commit 82edc9b3 authored by David Christie's avatar David Christie
Browse files

Add WorkSource capability to LocationManager

Change-Id: I0fbbad0879b87ecc75a503bf7963356595bf4b96
parent 757ec783
Loading
Loading
Loading
Loading
+16 −0
Original line number Diff line number Diff line
@@ -19,6 +19,7 @@ package android.location;
import android.os.Parcel;
import android.os.Parcelable;
import android.os.SystemClock;
import android.os.WorkSource;
import android.util.TimeUtils;


@@ -145,6 +146,7 @@ public final class LocationRequest implements Parcelable {
    private long mExpireAt = Long.MAX_VALUE;  // no expiry
    private int mNumUpdates = Integer.MAX_VALUE;  // no expiry
    private float mSmallestDisplacement = 0.0f;    // meters
    private WorkSource mWorkSource = new WorkSource();

    private String mProvider = LocationManager.FUSED_PROVIDER;  // for deprecated APIs that explicitly request a provider

@@ -233,6 +235,7 @@ public final class LocationRequest implements Parcelable {
        mNumUpdates = src.mNumUpdates;
        mSmallestDisplacement = src.mSmallestDisplacement;
        mProvider = src.mProvider;
        mWorkSource = src.mWorkSource;
    }

    /**
@@ -493,6 +496,16 @@ public final class LocationRequest implements Parcelable {
        return mSmallestDisplacement;
    }

    /** @hide */
    public void setWorkSource(WorkSource workSource) {
        mWorkSource = workSource;
    }

    /** @hide */
    public WorkSource getWorkSource() {
        return mWorkSource;
    }

    private static void checkInterval(long millis) {
        if (millis < 0) {
            throw new IllegalArgumentException("invalid interval: " + millis);
@@ -538,6 +551,8 @@ public final class LocationRequest implements Parcelable {
            request.setSmallestDisplacement(in.readFloat());
            String provider = in.readString();
            if (provider != null) request.setProvider(provider);
            WorkSource workSource = in.readParcelable(WorkSource.class.getClassLoader());
            if (workSource != null) request.setWorkSource(workSource);
            return request;
        }
        @Override
@@ -560,6 +575,7 @@ public final class LocationRequest implements Parcelable {
        parcel.writeInt(mNumUpdates);
        parcel.writeFloat(mSmallestDisplacement);
        parcel.writeString(mProvider);
        parcel.writeParcelable(mWorkSource, 0);
    }

    /** @hide */
+44 −12
Original line number Diff line number Diff line
@@ -458,6 +458,7 @@ public class LocationManagerService extends ILocationManager.Stub {

        final ILocationListener mListener;
        final PendingIntent mPendingIntent;
        final WorkSource mWorkSource; // WorkSource for battery blame, or null to assign to caller.
        final Object mKey;

        final HashMap<String,UpdateRecord> mUpdateRecords = new HashMap<String,UpdateRecord>();
@@ -467,7 +468,7 @@ public class LocationManagerService extends ILocationManager.Stub {
        PowerManager.WakeLock mWakeLock;

        Receiver(ILocationListener listener, PendingIntent intent, int pid, int uid,
                String packageName) {
                String packageName, WorkSource workSource) {
            mListener = listener;
            mPendingIntent = intent;
            if (listener != null) {
@@ -479,12 +480,19 @@ public class LocationManagerService extends ILocationManager.Stub {
            mUid = uid;
            mPid = pid;
            mPackageName = packageName;
            if (workSource != null && workSource.size() <= 0) {
                workSource = null;
            }
            mWorkSource = workSource;

            updateMonitoring(true);

            // construct/configure wakelock
            mWakeLock = mPowerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, WAKELOCK_KEY);
            mWakeLock.setWorkSource(new WorkSource(mUid, mPackageName));
            if (workSource == null) {
                workSource = new WorkSource(mUid, mPackageName);
            }
            mWakeLock.setWorkSource(workSource);
        }

        @Override
@@ -883,6 +891,15 @@ public class LocationManagerService extends ILocationManager.Stub {
        }
    }

    /**
     * Throw SecurityException if WorkSource use is not allowed (i.e. can't blame other packages
     * for battery).
     */
    private void checkWorkSourceAllowed() {
        mContext.enforceCallingOrSelfPermission(
                android.Manifest.permission.UPDATE_DEVICE_STATS, null);
    }

    public static int resolutionLevelToOp(int allowedResolutionLevel) {
        if (allowedResolutionLevel != RESOLUTION_LEVEL_NONE) {
            if (allowedResolutionLevel == RESOLUTION_LEVEL_COARSE) {
@@ -1124,7 +1141,15 @@ public class LocationManagerService extends ILocationManager.Stub {
                    if (UserHandle.getUserId(record.mReceiver.mUid) == mCurrentUserId) {
                        LocationRequest locationRequest = record.mRequest;
                        if (locationRequest.getInterval() <= thresholdInterval) {
                            worksource.add(record.mReceiver.mUid, record.mReceiver.mPackageName);
                            if (record.mReceiver.mWorkSource != null) {
                                // Assign blame to another work source.
                                worksource.add(record.mReceiver.mWorkSource);
                            } else {
                                // Assign blame to caller.
                                worksource.add(
                                        record.mReceiver.mUid,
                                        record.mReceiver.mPackageName);
                            }
                        }
                    }
                }
@@ -1199,11 +1224,11 @@ public class LocationManagerService extends ILocationManager.Stub {
    }

    private Receiver getReceiverLocked(ILocationListener listener, int pid, int uid,
            String packageName) {
            String packageName, WorkSource workSource) {
        IBinder binder = listener.asBinder();
        Receiver receiver = mReceivers.get(binder);
        if (receiver == null) {
            receiver = new Receiver(listener, null, pid, uid, packageName);
            receiver = new Receiver(listener, null, pid, uid, packageName, workSource);
            mReceivers.put(binder, receiver);

            try {
@@ -1216,10 +1241,11 @@ public class LocationManagerService extends ILocationManager.Stub {
        return receiver;
    }

    private Receiver getReceiverLocked(PendingIntent intent, int pid, int uid, String packageName) {
    private Receiver getReceiverLocked(PendingIntent intent, int pid, int uid, String packageName,
            WorkSource workSource) {
        Receiver receiver = mReceivers.get(intent);
        if (receiver == null) {
            receiver = new Receiver(null, intent, pid, uid, packageName);
            receiver = new Receiver(null, intent, pid, uid, packageName, workSource);
            mReceivers.put(intent, receiver);
        }
        return receiver;
@@ -1281,16 +1307,16 @@ public class LocationManagerService extends ILocationManager.Stub {
    }

    private Receiver checkListenerOrIntentLocked(ILocationListener listener, PendingIntent intent,
            int pid, int uid, String packageName) {
            int pid, int uid, String packageName, WorkSource workSource) {
        if (intent == null && listener == null) {
            throw new IllegalArgumentException("need either listener or intent");
        } else if (intent != null && listener != null) {
            throw new IllegalArgumentException("cannot register both listener and intent");
        } else if (intent != null) {
            checkPendingIntent(intent);
            return getReceiverLocked(intent, pid, uid, packageName);
            return getReceiverLocked(intent, pid, uid, packageName, workSource);
        } else {
            return getReceiverLocked(listener, pid, uid, packageName);
            return getReceiverLocked(listener, pid, uid, packageName, workSource);
        }
    }

@@ -1302,6 +1328,10 @@ public class LocationManagerService extends ILocationManager.Stub {
        int allowedResolutionLevel = getCallerAllowedResolutionLevel();
        checkResolutionLevelIsSufficientForProviderUse(allowedResolutionLevel,
                request.getProvider());
        WorkSource workSource = request.getWorkSource();
        if (workSource != null && workSource.size() > 0) {
            checkWorkSourceAllowed();
        }
        LocationRequest sanitizedRequest = createSanitizedRequest(request, allowedResolutionLevel);

        final int pid = Binder.getCallingPid();
@@ -1315,7 +1345,7 @@ public class LocationManagerService extends ILocationManager.Stub {

            synchronized (mLock) {
                Receiver recevier = checkListenerOrIntentLocked(listener, intent, pid, uid,
                        packageName);
                        packageName, workSource);
                requestLocationUpdatesLocked(sanitizedRequest, recevier, pid, uid, packageName);
            }
        } finally {
@@ -1364,7 +1394,9 @@ public class LocationManagerService extends ILocationManager.Stub {
        final int uid = Binder.getCallingUid();

        synchronized (mLock) {
            Receiver receiver = checkListenerOrIntentLocked(listener, intent, pid, uid, packageName);
            WorkSource workSource = null;
            Receiver receiver = checkListenerOrIntentLocked(listener, intent, pid, uid, packageName,
                    workSource);

            // providers may use public location API's, need to clear identity
            long identity = Binder.clearCallingIdentity();