App ops: you can now turn off operations.
Also add new ops for calendar and wi-fi scans, finish
implementing rejection of content provider calls, fix
issues with rejecting location calls, fix bug in the
new pm call to retrieve apps with permissions.
Change-Id: I29d9f8600bfbbf6561abf6d491907e2bbf6af417
diff --git a/api/current.txt b/api/current.txt
index 81e5d4f..0c9e16a 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -5122,6 +5122,7 @@
method public int bulkInsert(android.net.Uri, android.content.ContentValues[]);
method public android.os.Bundle call(java.lang.String, java.lang.String, android.os.Bundle);
method public abstract int delete(android.net.Uri, java.lang.String, java.lang.String[]);
+ method public void dump(java.io.FileDescriptor, java.io.PrintWriter, java.lang.String[]);
method public final android.content.Context getContext();
method public final android.content.pm.PathPermission[] getPathPermissions();
method public final java.lang.String getReadPermission();
diff --git a/core/java/android/app/AppOpsManager.java b/core/java/android/app/AppOpsManager.java
index 5d24d69..b1d0305 100644
--- a/core/java/android/app/AppOpsManager.java
+++ b/core/java/android/app/AppOpsManager.java
@@ -44,19 +44,44 @@
public static final int OP_WRITE_CONTACTS = 5;
public static final int OP_READ_CALL_LOG = 6;
public static final int OP_WRITE_CALL_LOG = 7;
+ public static final int OP_READ_CALENDAR = 8;
+ public static final int OP_WRITE_CALENDAR = 9;
+ public static final int OP_WIFI_SCAN = 10;
- public static String opToString(int op) {
- switch (op) {
- case OP_COARSE_LOCATION: return "COARSE_LOCATION";
- case OP_FINE_LOCATION: return "FINE_LOCATION";
- case OP_GPS: return "GPS";
- case OP_VIBRATE: return "VIBRATE";
- case OP_READ_CONTACTS: return "READ_CONTACTS";
- case OP_WRITE_CONTACTS: return "WRITE_CONTACTS";
- case OP_READ_CALL_LOG: return "READ_CALL_LOG";
- case OP_WRITE_CALL_LOG: return "WRITE_CALL_LOG";
- default: return "Unknown(" + op + ")";
- }
+ private static String[] sOpNames = new String[] {
+ "COARSE_LOCATION",
+ "FINE_LOCATION",
+ "GPS",
+ "VIBRATE",
+ "READ_CONTACTS",
+ "WRITE_CONTACTS",
+ "READ_CALL_LOG",
+ "WRITE_CALL_LOG",
+ "READ_CALENDAR",
+ "WRITE_CALENDAR",
+ "WIFI_SCAN",
+ };
+
+ private static String[] sOpPerms = new String[] {
+ android.Manifest.permission.ACCESS_COARSE_LOCATION,
+ android.Manifest.permission.ACCESS_FINE_LOCATION,
+ android.Manifest.permission.ACCESS_FINE_LOCATION,
+ android.Manifest.permission.VIBRATE,
+ android.Manifest.permission.READ_CONTACTS,
+ android.Manifest.permission.WRITE_CONTACTS,
+ android.Manifest.permission.READ_CALL_LOG,
+ android.Manifest.permission.WRITE_CALL_LOG,
+ android.Manifest.permission.READ_CALENDAR,
+ android.Manifest.permission.WRITE_CALENDAR,
+ android.Manifest.permission.ACCESS_WIFI_STATE,
+ };
+
+ public static String opToName(int op) {
+ return op < sOpNames.length ? sOpNames[op] : ("Unknown(" + op + ")");
+ }
+
+ public static String opToPermission(int op) {
+ return sOpPerms[op];
}
public static class PackageOps implements Parcelable {
@@ -120,12 +145,16 @@
public static class OpEntry implements Parcelable {
private final int mOp;
+ private final int mMode;
private final long mTime;
+ private final long mRejectTime;
private final int mDuration;
- public OpEntry(int op, long time, int duration) {
+ public OpEntry(int op, int mode, long time, long rejectTime, int duration) {
mOp = op;
+ mMode = mode;
mTime = time;
+ mRejectTime = rejectTime;
mDuration = duration;
}
@@ -133,10 +162,18 @@
return mOp;
}
+ public int getMode() {
+ return mMode;
+ }
+
public long getTime() {
return mTime;
}
+ public long getRejectTime() {
+ return mRejectTime;
+ }
+
public boolean isRunning() {
return mDuration == -1;
}
@@ -153,13 +190,17 @@
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeInt(mOp);
+ dest.writeInt(mMode);
dest.writeLong(mTime);
+ dest.writeLong(mRejectTime);
dest.writeInt(mDuration);
}
OpEntry(Parcel source) {
mOp = source.readInt();
+ mMode = source.readInt();
mTime = source.readLong();
+ mRejectTime = source.readLong();
mDuration = source.readInt();
}
@@ -195,6 +236,13 @@
return null;
}
+ public void setMode(int code, int uid, String packageName, int mode) {
+ try {
+ mService.setMode(code, uid, packageName, mode);
+ } catch (RemoteException e) {
+ }
+ }
+
public int checkOp(int op, int uid, String packageName) {
try {
int mode = mService.checkOperation(op, uid, packageName);
diff --git a/core/java/android/content/ContentProvider.java b/core/java/android/content/ContentProvider.java
index a6f7abc..4b977ab 100644
--- a/core/java/android/content/ContentProvider.java
+++ b/core/java/android/content/ContentProvider.java
@@ -190,8 +190,13 @@
public Cursor query(String callingPkg, Uri uri, String[] projection,
String selection, String[] selectionArgs, String sortOrder,
ICancellationSignal cancellationSignal) {
- // XXX need content provider to help return correct result.
- enforceReadPermission(callingPkg, uri);
+ if (enforceReadPermission(callingPkg, uri) != AppOpsManager.MODE_ALLOWED) {
+ // The read is not allowed... to fake it out, we replace the given
+ // selection statement with a dummy one that will always be false.
+ // This way we will get a cursor back that has the correct structure
+ // but contains no rows.
+ selection = "'A' = 'B'";
+ }
return ContentProvider.this.query(uri, projection, selection, selectionArgs, sortOrder,
CancellationSignal.fromTransport(cancellationSignal));
}
@@ -203,8 +208,14 @@
@Override
public Uri insert(String callingPkg, Uri uri, ContentValues initialValues) {
- // XXX need content provider to help return correct result.
- enforceWritePermission(callingPkg, uri);
+ if (enforceWritePermission(callingPkg, uri) != AppOpsManager.MODE_ALLOWED) {
+ // If not allowed, we need to return some reasonable URI. Maybe the
+ // content provider should be responsible for this, but for now we
+ // will just return the base URI with a dummy '0' tagged on to it.
+ // You shouldn't be able to read if you can't write, anyway, so it
+ // shouldn't matter much what is returned.
+ return uri.buildUpon().appendPath("0").build();
+ }
return ContentProvider.this.insert(uri, initialValues);
}
@@ -1189,12 +1200,10 @@
* Print the Provider's state into the given stream. This gets invoked if
* you run "adb shell dumpsys activity provider <provider_component_name>".
*
- * @param prefix Desired prefix to prepend at each line of output.
* @param fd The raw file descriptor that the dump is being sent to.
* @param writer The PrintWriter to which you should dump your state. This will be
* closed for you after you return.
* @param args additional arguments to the dump request.
- * @hide
*/
public void dump(FileDescriptor fd, PrintWriter writer, String[] args) {
writer.println("nothing to dump");
diff --git a/core/java/android/os/WorkSource.java b/core/java/android/os/WorkSource.java
index 69118fe..b79bdee 100644
--- a/core/java/android/os/WorkSource.java
+++ b/core/java/android/os/WorkSource.java
@@ -11,7 +11,7 @@
*/
public class WorkSource implements Parcelable {
static final String TAG = "WorkSource";
- static final boolean DEBUG = true;
+ static final boolean DEBUG = false;
int mNum;
int[] mUids;
diff --git a/core/java/com/android/internal/app/IAppOpsService.aidl b/core/java/com/android/internal/app/IAppOpsService.aidl
index a4eb4c5..c4f1bc48 100644
--- a/core/java/com/android/internal/app/IAppOpsService.aidl
+++ b/core/java/com/android/internal/app/IAppOpsService.aidl
@@ -21,6 +21,7 @@
interface IAppOpsService {
List<AppOpsManager.PackageOps> getPackagesForOps(in int[] ops);
List<AppOpsManager.PackageOps> getOpsForPackage(int uid, String packageName, in int[] ops);
+ void setMode(int code, int uid, String packageName, int mode);
int checkOperation(int code, int uid, String packageName);
int noteOperation(int code, int uid, String packageName);
int startOperation(int code, int uid, String packageName);
diff --git a/services/java/com/android/server/AppOpsService.java b/services/java/com/android/server/AppOpsService.java
index 3d9ddae..bf2a5ae 100644
--- a/services/java/com/android/server/AppOpsService.java
+++ b/services/java/com/android/server/AppOpsService.java
@@ -38,6 +38,7 @@
import android.os.ServiceManager;
import android.os.UserHandle;
import android.util.AtomicFile;
+import android.util.Log;
import android.util.Slog;
import android.util.SparseArray;
import android.util.TimeUtils;
@@ -93,12 +94,15 @@
final static class Op {
public final int op;
+ public int mode;
public int duration;
public long time;
+ public long rejectTime;
public int nesting;
public Op(int _op) {
op = _op;
+ mode = AppOpsManager.MODE_ALLOWED;
}
}
@@ -133,8 +137,8 @@
resOps = new ArrayList<AppOpsManager.OpEntry>();
for (int j=0; j<pkgOps.size(); j++) {
Op curOp = pkgOps.valueAt(j);
- resOps.add(new AppOpsManager.OpEntry(curOp.op, curOp.time,
- curOp.duration));
+ resOps.add(new AppOpsManager.OpEntry(curOp.op, curOp.mode, curOp.time,
+ curOp.rejectTime, curOp.duration));
}
} else {
for (int j=0; j<ops.length; j++) {
@@ -143,8 +147,8 @@
if (resOps == null) {
resOps = new ArrayList<AppOpsManager.OpEntry>();
}
- resOps.add(new AppOpsManager.OpEntry(curOp.op, curOp.time,
- curOp.duration));
+ resOps.add(new AppOpsManager.OpEntry(curOp.op, curOp.mode, curOp.time,
+ curOp.rejectTime, curOp.duration));
}
}
}
@@ -198,6 +202,20 @@
}
@Override
+ public void setMode(int code, int uid, String packageName, int mode) {
+ uid = handleIncomingUid(uid);
+ synchronized (this) {
+ Op op = getOpLocked(code, uid, packageName, true);
+ if (op != null) {
+ if (op.mode != mode) {
+ op.mode = mode;
+ scheduleWriteNowLocked();
+ }
+ }
+ }
+ }
+
+ @Override
public int checkOperation(int code, int uid, String packageName) {
uid = handleIncomingUid(uid);
synchronized (this) {
@@ -205,8 +223,8 @@
if (op == null) {
return AppOpsManager.MODE_ALLOWED;
}
+ return op.mode;
}
- return AppOpsManager.MODE_ALLOWED;
}
@Override
@@ -215,16 +233,26 @@
synchronized (this) {
Op op = getOpLocked(code, uid, packageName, true);
if (op == null) {
+ if (DEBUG) Log.d(TAG, "noteOperation: no op for code " + code + " uid " + uid
+ + " package " + packageName);
return AppOpsManager.MODE_IGNORED;
}
if (op.duration == -1) {
Slog.w(TAG, "Noting op not finished: uid " + uid + " pkg " + packageName
+ " code " + code + " time=" + op.time + " duration=" + op.duration);
}
- op.time = System.currentTimeMillis();
op.duration = 0;
+ if (op.mode != AppOpsManager.MODE_ALLOWED) {
+ if (DEBUG) Log.d(TAG, "noteOperation: reject #" + op.mode + " for code " + code
+ + " uid " + uid + " package " + packageName);
+ op.rejectTime = System.currentTimeMillis();
+ return op.mode;
+ }
+ if (DEBUG) Log.d(TAG, "noteOperation: allowing code " + code + " uid " + uid
+ + " package " + packageName);
+ op.time = System.currentTimeMillis();
+ return AppOpsManager.MODE_ALLOWED;
}
- return AppOpsManager.MODE_ALLOWED;
}
@Override
@@ -233,15 +261,25 @@
synchronized (this) {
Op op = getOpLocked(code, uid, packageName, true);
if (op == null) {
+ if (DEBUG) Log.d(TAG, "startOperation: no op for code " + code + " uid " + uid
+ + " package " + packageName);
return AppOpsManager.MODE_IGNORED;
}
+ if (op.mode != AppOpsManager.MODE_ALLOWED) {
+ if (DEBUG) Log.d(TAG, "startOperation: reject #" + op.mode + " for code " + code
+ + " uid " + uid + " package " + packageName);
+ op.rejectTime = System.currentTimeMillis();
+ return op.mode;
+ }
+ if (DEBUG) Log.d(TAG, "startOperation: allowing code " + code + " uid " + uid
+ + " package " + packageName);
if (op.nesting == 0) {
op.time = System.currentTimeMillis();
op.duration = -1;
}
op.nesting++;
+ return AppOpsManager.MODE_ALLOWED;
}
- return AppOpsManager.MODE_ALLOWED;
}
@Override
@@ -319,6 +357,21 @@
return ops;
}
+ private void scheduleWriteLocked() {
+ if (!mWriteScheduled) {
+ mWriteScheduled = true;
+ mHandler.postDelayed(mWriteRunner, WRITE_DELAY);
+ }
+ }
+
+ private void scheduleWriteNowLocked() {
+ if (!mWriteScheduled) {
+ mWriteScheduled = true;
+ }
+ mHandler.removeCallbacks(mWriteRunner);
+ mHandler.post(mWriteRunner);
+ }
+
private Op getOpLocked(int code, int uid, String packageName, boolean edit) {
Ops ops = getOpsLocked(uid, packageName, edit);
if (ops == null) {
@@ -332,9 +385,8 @@
op = new Op(code);
ops.put(code, op);
}
- if (edit && !mWriteScheduled) {
- mWriteScheduled = true;
- mHandler.postDelayed(mWriteRunner, WRITE_DELAY);
+ if (edit) {
+ scheduleWriteLocked();
}
return op;
}
@@ -441,8 +493,22 @@
String tagName = parser.getName();
if (tagName.equals("op")) {
Op op = new Op(Integer.parseInt(parser.getAttributeValue(null, "n")));
- op.time = Long.parseLong(parser.getAttributeValue(null, "t"));
- op.duration = Integer.parseInt(parser.getAttributeValue(null, "d"));
+ String mode = parser.getAttributeValue(null, "m");
+ if (mode != null) {
+ op.mode = Integer.parseInt(mode);
+ }
+ String time = parser.getAttributeValue(null, "t");
+ if (time != null) {
+ op.time = Long.parseLong(time);
+ }
+ time = parser.getAttributeValue(null, "r");
+ if (time != null) {
+ op.rejectTime = Long.parseLong(time);
+ }
+ String dur = parser.getAttributeValue(null, "d");
+ if (dur != null) {
+ op.duration = Integer.parseInt(dur);
+ }
HashMap<String, Ops> pkgOps = mUidOps.get(uid);
if (pkgOps == null) {
pkgOps = new HashMap<String, Ops>();
@@ -499,8 +565,21 @@
AppOpsManager.OpEntry op = ops.get(j);
out.startTag(null, "op");
out.attribute(null, "n", Integer.toString(op.getOp()));
- out.attribute(null, "t", Long.toString(op.getTime()));
- out.attribute(null, "d", Integer.toString(op.getDuration()));
+ if (op.getMode() != AppOpsManager.MODE_ALLOWED) {
+ out.attribute(null, "m", Integer.toString(op.getMode()));
+ }
+ long time = op.getTime();
+ if (time != 0) {
+ out.attribute(null, "t", Long.toString(time));
+ }
+ time = op.getRejectTime();
+ if (time != 0) {
+ out.attribute(null, "r", Long.toString(time));
+ }
+ int dur = op.getDuration();
+ if (dur != 0) {
+ out.attribute(null, "d", Integer.toString(dur));
+ }
out.endTag(null, "op");
}
out.endTag(null, "uid");
@@ -532,6 +611,7 @@
synchronized (this) {
pw.println("Current AppOps Service state:");
+ final long now = System.currentTimeMillis();
for (int i=0; i<mUidOps.size(); i++) {
pw.print(" Uid "); UserHandle.formatUid(pw, mUidOps.keyAt(i)); pw.println(":");
HashMap<String, Ops> pkgOps = mUidOps.valueAt(i);
@@ -539,10 +619,16 @@
pw.print(" Package "); pw.print(ops.packageName); pw.println(":");
for (int j=0; j<ops.size(); j++) {
Op op = ops.valueAt(j);
- pw.print(" "); pw.print(AppOpsManager.opToString(op.op));
- pw.print(": time=");
- TimeUtils.formatDuration(System.currentTimeMillis()-op.time, pw);
- pw.print(" ago");
+ pw.print(" "); pw.print(AppOpsManager.opToName(op.op));
+ pw.print(": mode="); pw.print(op.mode);
+ if (op.time != 0) {
+ pw.print("; time="); TimeUtils.formatDuration(now-op.time, pw);
+ pw.print(" ago");
+ }
+ if (op.rejectTime != 0) {
+ pw.print("; rejectTime="); TimeUtils.formatDuration(now-op.rejectTime, pw);
+ pw.print(" ago");
+ }
if (op.duration == -1) {
pw.println(" (running)");
} else {
diff --git a/services/java/com/android/server/LocationManagerService.java b/services/java/com/android/server/LocationManagerService.java
index b351fc2..f63719e 100644
--- a/services/java/com/android/server/LocationManagerService.java
+++ b/services/java/com/android/server/LocationManagerService.java
@@ -529,9 +529,6 @@
}
public boolean callLocationChangedLocked(Location location) {
- if (!reportLocationAccessNoThrow(mUid, mPackageName, mAllowedResolutionLevel)) {
- return true;
- }
if (mListener != null) {
try {
synchronized (this) {
@@ -802,14 +799,20 @@
}
}
- boolean reportLocationAccessNoThrow(int uid, String packageName, int allowedResolutionLevel) {
- int op;
+ public static int resolutionLevelToOp(int allowedResolutionLevel) {
if (allowedResolutionLevel != RESOLUTION_LEVEL_NONE) {
if (allowedResolutionLevel == RESOLUTION_LEVEL_COARSE) {
- op = AppOpsManager.OP_COARSE_LOCATION;
+ return AppOpsManager.OP_COARSE_LOCATION;
} else {
- op = AppOpsManager.OP_FINE_LOCATION;
+ return AppOpsManager.OP_FINE_LOCATION;
}
+ }
+ return -1;
+ }
+
+ boolean reportLocationAccessNoThrow(int uid, String packageName, int allowedResolutionLevel) {
+ int op = resolutionLevelToOp(allowedResolutionLevel);
+ if (op >= 0) {
if (mAppOps.noteOpNoThrow(op, uid, packageName) != AppOpsManager.MODE_ALLOWED) {
return false;
}
@@ -818,13 +821,8 @@
}
boolean checkLocationAccess(int uid, String packageName, int allowedResolutionLevel) {
- int op;
- if (allowedResolutionLevel != RESOLUTION_LEVEL_NONE) {
- if (allowedResolutionLevel == RESOLUTION_LEVEL_COARSE) {
- op = AppOpsManager.OP_COARSE_LOCATION;
- } else {
- op = AppOpsManager.OP_FINE_LOCATION;
- }
+ int op = resolutionLevelToOp(allowedResolutionLevel);
+ if (op >= 0) {
if (mAppOps.checkOp(op, uid, packageName) != AppOpsManager.MODE_ALLOWED) {
return false;
}
@@ -1019,11 +1017,14 @@
if (records != null) {
for (UpdateRecord record : records) {
if (UserHandle.getUserId(record.mReceiver.mUid) == mCurrentUserId) {
- LocationRequest locationRequest = record.mRequest;
- providerRequest.locationRequests.add(locationRequest);
- if (locationRequest.getInterval() < providerRequest.interval) {
- providerRequest.reportLocation = true;
- providerRequest.interval = locationRequest.getInterval();
+ if (checkLocationAccess(record.mReceiver.mUid, record.mReceiver.mPackageName,
+ record.mReceiver.mAllowedResolutionLevel)) {
+ LocationRequest locationRequest = record.mRequest;
+ providerRequest.locationRequests.add(locationRequest);
+ if (locationRequest.getInterval() < providerRequest.interval) {
+ providerRequest.reportLocation = true;
+ providerRequest.interval = locationRequest.getInterval();
+ }
}
}
}
@@ -1144,9 +1145,6 @@
* and consistency requirements.
*
* @param request the LocationRequest from which to create a sanitized version
- * @param shouldBeCoarse whether the sanitized version should be held to coarse resolution
- * constraints
- * @param fastestCoarseIntervalMS minimum interval allowed for coarse resolution
* @return a version of request that meets the given resolution and consistency requirements
* @hide
*/
@@ -1340,16 +1338,18 @@
final int uid = Binder.getCallingUid();
final long identity = Binder.clearCallingIdentity();
try {
- if (!reportLocationAccessNoThrow(uid, packageName, allowedResolutionLevel)) {
- return null;
- }
-
if (mBlacklist.isBlacklisted(packageName)) {
if (D) Log.d(TAG, "not returning last loc for blacklisted app: " +
packageName);
return null;
}
+ if (!reportLocationAccessNoThrow(uid, packageName, allowedResolutionLevel)) {
+ if (D) Log.d(TAG, "not returning last loc for no op app: " +
+ packageName);
+ return null;
+ }
+
synchronized (mLock) {
// Figure out the provider. Either its explicitly request (deprecated API's),
// or use the fused provider
@@ -1402,7 +1402,8 @@
}
long identity = Binder.clearCallingIdentity();
try {
- mGeofenceManager.addFence(sanitizedRequest, geofence, intent, uid, packageName);
+ mGeofenceManager.addFence(sanitizedRequest, geofence, intent, allowedResolutionLevel,
+ uid, packageName);
} finally {
Binder.restoreCallingIdentity(identity);
}
@@ -1703,6 +1704,13 @@
continue;
}
+ if (!reportLocationAccessNoThrow(receiver.mUid, receiver.mPackageName,
+ receiver.mAllowedResolutionLevel)) {
+ if (D) Log.d(TAG, "skipping loc update for no op app: " +
+ receiver.mPackageName);
+ continue;
+ }
+
Location notifyLocation = null;
if (receiver.mAllowedResolutionLevel < RESOLUTION_LEVEL_FINE) {
notifyLocation = coarseLocation; // use coarse location
diff --git a/services/java/com/android/server/WifiService.java b/services/java/com/android/server/WifiService.java
index 5789a53..ad6eb4d 100644
--- a/services/java/com/android/server/WifiService.java
+++ b/services/java/com/android/server/WifiService.java
@@ -18,6 +18,7 @@
import android.app.ActivityManager;
import android.app.AlarmManager;
+import android.app.AppOpsManager;
import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
@@ -127,6 +128,7 @@
private int mMulticastDisabled;
private final IBatteryStats mBatteryStats;
+ private final AppOpsManager mAppOps;
private boolean mEnableTrafficStatsPoll = false;
private int mTrafficStatsPollToken = 0;
@@ -381,6 +383,7 @@
mWifiStateMachine = new WifiStateMachine(mContext, mInterfaceName);
mWifiStateMachine.enableRssiPolling(true);
mBatteryStats = BatteryStatsService.getService();
+ mAppOps = (AppOpsManager)context.getSystemService(Context.APP_OPS_SERVICE);
mAlarmManager = (AlarmManager)mContext.getSystemService(Context.ALARM_SERVICE);
Intent idleIntent = new Intent(ACTION_DEVICE_IDLE, null);
@@ -845,10 +848,15 @@
* a list of {@link ScanResult} objects.
* @return the list of results
*/
- public List<ScanResult> getScanResults() {
+ public List<ScanResult> getScanResults(String callingPackage) {
enforceAccessPermission();
int userId = UserHandle.getCallingUserId();
+ int uid = Binder.getCallingUid();
long ident = Binder.clearCallingIdentity();
+ if (mAppOps.noteOp(AppOpsManager.OP_WIFI_SCAN, uid, callingPackage)
+ != AppOpsManager.MODE_ALLOWED) {
+ return new ArrayList<ScanResult>();
+ }
try {
int currentUser = ActivityManager.getCurrentUser();
if (userId != currentUser) {
diff --git a/services/java/com/android/server/location/GeofenceManager.java b/services/java/com/android/server/location/GeofenceManager.java
index f9be719..e24bf76 100644
--- a/services/java/com/android/server/location/GeofenceManager.java
+++ b/services/java/com/android/server/location/GeofenceManager.java
@@ -21,6 +21,7 @@
import java.util.LinkedList;
import java.util.List;
+import android.app.AppOpsManager;
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
@@ -68,6 +69,7 @@
private final Context mContext;
private final LocationManager mLocationManager;
+ private final AppOpsManager mAppOps;
private final PowerManager.WakeLock mWakeLock;
private final GeofenceHandler mHandler;
private final LocationBlacklist mBlacklist;
@@ -107,6 +109,7 @@
public GeofenceManager(Context context, LocationBlacklist blacklist) {
mContext = context;
mLocationManager = (LocationManager) mContext.getSystemService(Context.LOCATION_SERVICE);
+ mAppOps = (AppOpsManager)mContext.getSystemService(Context.APP_OPS_SERVICE);
PowerManager powerManager = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
mWakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, TAG);
mHandler = new GeofenceHandler();
@@ -114,14 +117,14 @@
}
public void addFence(LocationRequest request, Geofence geofence, PendingIntent intent,
- int uid, String packageName) {
+ int allowedResolutionLevel, int uid, String packageName) {
if (D) {
Slog.d(TAG, "addFence: request=" + request + ", geofence=" + geofence
+ ", intent=" + intent + ", uid=" + uid + ", packageName=" + packageName);
}
GeofenceState state = new GeofenceState(geofence,
- request.getExpireAt(), packageName, intent);
+ request.getExpireAt(), allowedResolutionLevel, uid, packageName, intent);
synchronized (mLock) {
// first make sure it doesn't already exist
for (int i = mFences.size() - 1; i >= 0; i--) {
@@ -261,6 +264,18 @@
continue;
}
+ int op = LocationManagerService.resolutionLevelToOp(state.mAllowedResolutionLevel);
+ if (op >= 0) {
+ if (mAppOps.noteOpNoThrow(AppOpsManager.OP_FINE_LOCATION, state.mUid,
+ state.mPackageName) != AppOpsManager.MODE_ALLOWED) {
+ if (D) {
+ Slog.d(TAG, "skipping geofence processing for no op app: "
+ + state.mPackageName);
+ }
+ continue;
+ }
+ }
+
needUpdates = true;
if (location != null) {
int event = state.processLocation(location);
diff --git a/services/java/com/android/server/location/GeofenceState.java b/services/java/com/android/server/location/GeofenceState.java
index 11705ff..3ebe20a 100644
--- a/services/java/com/android/server/location/GeofenceState.java
+++ b/services/java/com/android/server/location/GeofenceState.java
@@ -35,6 +35,8 @@
public final Geofence mFence;
private final Location mLocation;
public final long mExpireAt;
+ public final int mAllowedResolutionLevel;
+ public final int mUid;
public final String mPackageName;
public final PendingIntent mIntent;
@@ -42,12 +44,14 @@
double mDistanceToCenter; // current distance to center of fence
public GeofenceState(Geofence fence, long expireAt,
- String packageName, PendingIntent intent) {
+ int allowedResolutionLevel, int uid, String packageName, PendingIntent intent) {
mState = STATE_UNKNOWN;
mDistanceToCenter = Double.MAX_VALUE;
mFence = fence;
mExpireAt = expireAt;
+ mAllowedResolutionLevel = allowedResolutionLevel;
+ mUid = uid;
mPackageName = packageName;
mIntent = intent;
diff --git a/services/java/com/android/server/location/LocationBlacklist.java b/services/java/com/android/server/location/LocationBlacklist.java
index 2437a37..6f22689 100644
--- a/services/java/com/android/server/location/LocationBlacklist.java
+++ b/services/java/com/android/server/location/LocationBlacklist.java
@@ -67,9 +67,9 @@
private void reloadBlacklistLocked() {
mWhitelist = getStringArrayLocked(WHITELIST_CONFIG_NAME);
- Slog.i(TAG, "whitelist: " + Arrays.toString(mWhitelist));
+ if (D) Slog.d(TAG, "whitelist: " + Arrays.toString(mWhitelist));
mBlacklist = getStringArrayLocked(BLACKLIST_CONFIG_NAME);
- Slog.i(TAG, "blacklist: " + Arrays.toString(mBlacklist));
+ if (D) Slog.d(TAG, "blacklist: " + Arrays.toString(mBlacklist));
}
private void reloadBlacklist() {
diff --git a/services/java/com/android/server/pm/PackageManagerService.java b/services/java/com/android/server/pm/PackageManagerService.java
index b893062..626002d 100644
--- a/services/java/com/android/server/pm/PackageManagerService.java
+++ b/services/java/com/android/server/pm/PackageManagerService.java
@@ -1348,7 +1348,8 @@
continue;
}
- if (!ps.grantedPermissions
+ final GrantedPermissions gp = ps.sharedUser != null ? ps.sharedUser : ps;
+ if (!gp.grantedPermissions
.contains(android.Manifest.permission.PACKAGE_VERIFICATION_AGENT)) {
continue;
}
@@ -2918,8 +2919,9 @@
private void addPackageHoldingPermissions(ArrayList<PackageInfo> list, PackageSetting ps,
String[] permissions, boolean[] tmp, int flags, int userId) {
int numMatch = 0;
+ final GrantedPermissions gp = ps.sharedUser != null ? ps.sharedUser : ps;
for (int i=0; i<permissions.length; i++) {
- if (ps.grantedPermissions.contains(permissions[i])) {
+ if (gp.grantedPermissions.contains(permissions[i])) {
tmp[i] = true;
numMatch++;
} else {
diff --git a/wifi/java/android/net/wifi/IWifiManager.aidl b/wifi/java/android/net/wifi/IWifiManager.aidl
index 55de065..0be453c 100644
--- a/wifi/java/android/net/wifi/IWifiManager.aidl
+++ b/wifi/java/android/net/wifi/IWifiManager.aidl
@@ -45,7 +45,7 @@
void startScan(boolean forceActive);
- List<ScanResult> getScanResults();
+ List<ScanResult> getScanResults(String callingPackage);
void disconnect();
diff --git a/wifi/java/android/net/wifi/WifiManager.java b/wifi/java/android/net/wifi/WifiManager.java
index 4861759..c08db07 100644
--- a/wifi/java/android/net/wifi/WifiManager.java
+++ b/wifi/java/android/net/wifi/WifiManager.java
@@ -777,7 +777,7 @@
*/
public List<ScanResult> getScanResults() {
try {
- return mService.getScanResults();
+ return mService.getScanResults(mContext.getBasePackageName());
} catch (RemoteException e) {
return null;
}