summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDavid Christie <dnchrist@google.com>2013-07-19 11:31:42 -0700
committerDavid Christie <dnchrist@google.com>2013-07-22 16:50:13 -0700
commit82edc9b3482307a8e93655aadabb4f9ad24efe46 (patch)
treecb82eabd1b6c11293eb6cb0dbea2e6ad00ca7d2b
parent757ec7837db85eae675cda5cfaf94040268327fd (diff)
downloadframeworks_base-82edc9b3482307a8e93655aadabb4f9ad24efe46.zip
frameworks_base-82edc9b3482307a8e93655aadabb4f9ad24efe46.tar.gz
frameworks_base-82edc9b3482307a8e93655aadabb4f9ad24efe46.tar.bz2
Add WorkSource capability to LocationManager
Change-Id: I0fbbad0879b87ecc75a503bf7963356595bf4b96
-rw-r--r--location/java/android/location/LocationRequest.java16
-rw-r--r--services/java/com/android/server/LocationManagerService.java56
2 files changed, 60 insertions, 12 deletions
diff --git a/location/java/android/location/LocationRequest.java b/location/java/android/location/LocationRequest.java
index 68f540b..5ebba93 100644
--- a/location/java/android/location/LocationRequest.java
+++ b/location/java/android/location/LocationRequest.java
@@ -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 */
diff --git a/services/java/com/android/server/LocationManagerService.java b/services/java/com/android/server/LocationManagerService.java
index bde9e1c..d3dcd69 100644
--- a/services/java/com/android/server/LocationManagerService.java
+++ b/services/java/com/android/server/LocationManagerService.java
@@ -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();