summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--cmds/content/src/com/android/commands/content/Content.java8
-rw-r--r--cmds/settings/src/com/android/commands/settings/SettingsCmd.java4
-rw-r--r--core/java/android/app/AppOpsManager.aidl20
-rw-r--r--core/java/android/app/AppOpsManager.java166
-rw-r--r--core/java/android/app/ContextImpl.java4
-rw-r--r--core/java/android/content/ContentProvider.java105
-rw-r--r--core/java/android/content/ContentProviderClient.java24
-rw-r--r--core/java/android/content/ContentProviderNative.java67
-rw-r--r--core/java/android/content/ContentResolver.java29
-rw-r--r--core/java/android/content/IContentProvider.java27
-rw-r--r--core/java/android/provider/Settings.java18
-rw-r--r--core/java/com/android/internal/app/IAppOpsService.aidl6
-rw-r--r--core/res/AndroidManifest.xml7
-rw-r--r--core/res/res/values/strings.xml6
-rw-r--r--media/java/android/media/MediaInserter.java10
-rw-r--r--media/java/android/media/MediaScanner.java50
-rw-r--r--media/java/android/mtp/MtpDatabase.java43
-rw-r--r--media/java/android/mtp/MtpPropertyGroup.java16
-rw-r--r--services/java/com/android/server/AppOpsService.java366
-rw-r--r--services/java/com/android/server/LocationManagerService.java44
-rw-r--r--services/java/com/android/server/am/ActivityManagerService.java4
-rw-r--r--test-runner/src/android/test/mock/MockContentProvider.java31
-rw-r--r--test-runner/src/android/test/mock/MockIContentProvider.java27
-rw-r--r--tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContentProvider.java34
24 files changed, 868 insertions, 248 deletions
diff --git a/cmds/content/src/com/android/commands/content/Content.java b/cmds/content/src/com/android/commands/content/Content.java
index 4baea77..2ae2071 100644
--- a/cmds/content/src/com/android/commands/content/Content.java
+++ b/cmds/content/src/com/android/commands/content/Content.java
@@ -358,7 +358,7 @@ public class Content {
@Override
public void onExecute(IContentProvider provider) throws Exception {
- provider.insert(mUri, mContentValues);
+ provider.insert(null, mUri, mContentValues);
}
}
@@ -372,7 +372,7 @@ public class Content {
@Override
public void onExecute(IContentProvider provider) throws Exception {
- provider.delete(mUri, mWhere, null);
+ provider.delete(null, mUri, mWhere, null);
}
}
@@ -389,7 +389,7 @@ public class Content {
@Override
public void onExecute(IContentProvider provider) throws Exception {
- Cursor cursor = provider.query(mUri, mProjection, mWhere, null, mSortOrder, null);
+ Cursor cursor = provider.query(null, mUri, mProjection, mWhere, null, mSortOrder, null);
if (cursor == null) {
System.out.println("No result found.");
return;
@@ -451,7 +451,7 @@ public class Content {
@Override
public void onExecute(IContentProvider provider) throws Exception {
- provider.update(mUri, mContentValues, mWhere, null);
+ provider.update(null, mUri, mContentValues, mWhere, null);
}
}
diff --git a/cmds/settings/src/com/android/commands/settings/SettingsCmd.java b/cmds/settings/src/com/android/commands/settings/SettingsCmd.java
index 0c69f01..dce0a75 100644
--- a/cmds/settings/src/com/android/commands/settings/SettingsCmd.java
+++ b/cmds/settings/src/com/android/commands/settings/SettingsCmd.java
@@ -180,7 +180,7 @@ public final class SettingsCmd {
try {
Bundle arg = new Bundle();
arg.putInt(Settings.CALL_METHOD_USER_KEY, userHandle);
- Bundle b = provider.call(callGetCommand, key, arg);
+ Bundle b = provider.call(null, callGetCommand, key, arg);
if (b != null) {
result = b.getPairValue();
}
@@ -205,7 +205,7 @@ public final class SettingsCmd {
Bundle arg = new Bundle();
arg.putString(Settings.NameValueTable.VALUE, value);
arg.putInt(Settings.CALL_METHOD_USER_KEY, userHandle);
- provider.call(callPutCommand, key, arg);
+ provider.call(null, callPutCommand, key, arg);
} catch (RemoteException e) {
System.err.println("Can't set key " + key + " in " + table + " for user " + userHandle);
}
diff --git a/core/java/android/app/AppOpsManager.aidl b/core/java/android/app/AppOpsManager.aidl
new file mode 100644
index 0000000..4b97a15
--- /dev/null
+++ b/core/java/android/app/AppOpsManager.aidl
@@ -0,0 +1,20 @@
+/**
+ * Copyright (c) 2013, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.app;
+
+parcelable AppOpsManager.PackageOps;
+parcelable AppOpsManager.OpEntry;
diff --git a/core/java/android/app/AppOpsManager.java b/core/java/android/app/AppOpsManager.java
index 7210df4..4cea6a0 100644
--- a/core/java/android/app/AppOpsManager.java
+++ b/core/java/android/app/AppOpsManager.java
@@ -18,7 +18,12 @@ package android.app;
import com.android.internal.app.IAppOpsService;
+import java.util.ArrayList;
+import java.util.List;
+
import android.content.Context;
+import android.os.Parcel;
+import android.os.Parcelable;
import android.os.Process;
import android.os.RemoteException;
@@ -31,24 +36,177 @@ public class AppOpsManager {
public static final int MODE_IGNORED = 1;
public static final int MODE_ERRORED = 2;
- public static final int OP_LOCATION = 0;
- public static final int OP_GPS = 1;
- public static final int OP_VIBRATE = 2;
+ public static final int OP_COARSE_LOCATION = 0;
+ public static final int OP_FINE_LOCATION = 1;
+ public static final int OP_GPS = 2;
+ public static final int OP_VIBRATE = 3;
+ public static final int OP_READ_CONTACTS = 4;
+ 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 String opToString(int op) {
switch (op) {
- case OP_LOCATION: return "LOCATION";
+ 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 + ")";
}
}
+ public static class PackageOps implements Parcelable {
+ private final String mPackageName;
+ private final int mUid;
+ private final List<OpEntry> mEntries;
+
+ public PackageOps(String packageName, int uid, List<OpEntry> entries) {
+ mPackageName = packageName;
+ mUid = uid;
+ mEntries = entries;
+ }
+
+ public String getPackageName() {
+ return mPackageName;
+ }
+
+ public int getUid() {
+ return mUid;
+ }
+
+ public List<OpEntry> getOps() {
+ return mEntries;
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeString(mPackageName);
+ dest.writeInt(mUid);
+ dest.writeInt(mEntries.size());
+ for (int i=0; i<mEntries.size(); i++) {
+ mEntries.get(i).writeToParcel(dest, flags);
+ }
+ }
+
+ PackageOps(Parcel source) {
+ mPackageName = source.readString();
+ mUid = source.readInt();
+ mEntries = new ArrayList<OpEntry>();
+ final int N = source.readInt();
+ for (int i=0; i<N; i++) {
+ mEntries.add(OpEntry.CREATOR.createFromParcel(source));
+ }
+ }
+
+ public static final Creator<PackageOps> CREATOR = new Creator<PackageOps>() {
+ @Override public PackageOps createFromParcel(Parcel source) {
+ return new PackageOps(source);
+ }
+
+ @Override public PackageOps[] newArray(int size) {
+ return new PackageOps[size];
+ }
+ };
+ }
+
+ public static class OpEntry implements Parcelable {
+ private final int mOp;
+ private final long mTime;
+ private final int mDuration;
+
+ public OpEntry(int op, long time, int duration) {
+ mOp = op;
+ mTime = time;
+ mDuration = duration;
+ }
+
+ public int getOp() {
+ return mOp;
+ }
+
+ public long getTime() {
+ return mTime;
+ }
+
+ public boolean isRunning() {
+ return mDuration == -1;
+ }
+
+ public int getDuration() {
+ return mDuration == -1 ? (int)(System.currentTimeMillis()-mTime) : mDuration;
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeInt(mOp);
+ dest.writeLong(mTime);
+ dest.writeInt(mDuration);
+ }
+
+ OpEntry(Parcel source) {
+ mOp = source.readInt();
+ mTime = source.readLong();
+ mDuration = source.readInt();
+ }
+
+ public static final Creator<OpEntry> CREATOR = new Creator<OpEntry>() {
+ @Override public OpEntry createFromParcel(Parcel source) {
+ return new OpEntry(source);
+ }
+
+ @Override public OpEntry[] newArray(int size) {
+ return new OpEntry[size];
+ }
+ };
+ }
+
public AppOpsManager(Context context, IAppOpsService service) {
mContext = context;
mService = service;
}
+ public List<AppOpsManager.PackageOps> getPackagesForOps(int[] ops) {
+ try {
+ return mService.getPackagesForOps(ops);
+ } catch (RemoteException e) {
+ }
+ return null;
+ }
+
+ public int checkOp(int op, int uid, String packageName) {
+ try {
+ int mode = mService.checkOperation(op, uid, packageName);
+ if (mode == MODE_ERRORED) {
+ throw new SecurityException("Operation not allowed");
+ }
+ return mode;
+ } catch (RemoteException e) {
+ }
+ return MODE_IGNORED;
+ }
+
+ public int checkOpNoThrow(int op, int uid, String packageName) {
+ try {
+ return mService.checkOperation(op, uid, packageName);
+ } catch (RemoteException e) {
+ }
+ return MODE_IGNORED;
+ }
+
public int noteOp(int op, int uid, String packageName) {
try {
int mode = mService.noteOperation(op, uid, packageName);
diff --git a/core/java/android/app/ContextImpl.java b/core/java/android/app/ContextImpl.java
index 99ac0d6..1d394e8 100644
--- a/core/java/android/app/ContextImpl.java
+++ b/core/java/android/app/ContextImpl.java
@@ -623,7 +623,9 @@ class ContextImpl extends Context {
if (mPackageInfo != null) {
return mPackageInfo.getPackageName();
}
- throw new RuntimeException("Not supported in system context");
+ // No mPackageInfo means this is a Context for the system itself,
+ // and this here is its name.
+ return "android";
}
@Override
diff --git a/core/java/android/content/ContentProvider.java b/core/java/android/content/ContentProvider.java
index c1411b0..a6f7abc 100644
--- a/core/java/android/content/ContentProvider.java
+++ b/core/java/android/content/ContentProvider.java
@@ -18,6 +18,7 @@ package android.content;
import static android.content.pm.PackageManager.PERMISSION_GRANTED;
+import android.app.AppOpsManager;
import android.content.pm.PackageManager;
import android.content.pm.PathPermission;
import android.content.pm.ProviderInfo;
@@ -172,6 +173,10 @@ public abstract class ContentProvider implements ComponentCallbacks2 {
* @hide
*/
class Transport extends ContentProviderNative {
+ AppOpsManager mAppOpsManager = null;
+ int mReadOp = -1;
+ int mWriteOp = -1;
+
ContentProvider getContentProvider() {
return ContentProvider.this;
}
@@ -182,10 +187,11 @@ public abstract class ContentProvider implements ComponentCallbacks2 {
}
@Override
- public Cursor query(Uri uri, String[] projection,
+ public Cursor query(String callingPkg, Uri uri, String[] projection,
String selection, String[] selectionArgs, String sortOrder,
ICancellationSignal cancellationSignal) {
- enforceReadPermission(uri);
+ // XXX need content provider to help return correct result.
+ enforceReadPermission(callingPkg, uri);
return ContentProvider.this.query(uri, projection, selection, selectionArgs, sortOrder,
CancellationSignal.fromTransport(cancellationSignal));
}
@@ -196,63 +202,75 @@ public abstract class ContentProvider implements ComponentCallbacks2 {
}
@Override
- public Uri insert(Uri uri, ContentValues initialValues) {
- enforceWritePermission(uri);
+ public Uri insert(String callingPkg, Uri uri, ContentValues initialValues) {
+ // XXX need content provider to help return correct result.
+ enforceWritePermission(callingPkg, uri);
return ContentProvider.this.insert(uri, initialValues);
}
@Override
- public int bulkInsert(Uri uri, ContentValues[] initialValues) {
- enforceWritePermission(uri);
+ public int bulkInsert(String callingPkg, Uri uri, ContentValues[] initialValues) {
+ if (enforceWritePermission(callingPkg, uri) != AppOpsManager.MODE_ALLOWED) {
+ return 0;
+ }
return ContentProvider.this.bulkInsert(uri, initialValues);
}
@Override
- public ContentProviderResult[] applyBatch(ArrayList<ContentProviderOperation> operations)
+ public ContentProviderResult[] applyBatch(String callingPkg,
+ ArrayList<ContentProviderOperation> operations)
throws OperationApplicationException {
for (ContentProviderOperation operation : operations) {
if (operation.isReadOperation()) {
- enforceReadPermission(operation.getUri());
+ if (enforceReadPermission(callingPkg, operation.getUri())
+ != AppOpsManager.MODE_ALLOWED) {
+ throw new OperationApplicationException("App op not allowed", 0);
+ }
}
if (operation.isWriteOperation()) {
- enforceWritePermission(operation.getUri());
+ if (enforceWritePermission(callingPkg, operation.getUri())
+ != AppOpsManager.MODE_ALLOWED) {
+ throw new OperationApplicationException("App op not allowed", 0);
+ }
}
}
return ContentProvider.this.applyBatch(operations);
}
@Override
- public int delete(Uri uri, String selection, String[] selectionArgs) {
- enforceWritePermission(uri);
+ public int delete(String callingPkg, Uri uri, String selection, String[] selectionArgs) {
+ if (enforceWritePermission(callingPkg, uri) != AppOpsManager.MODE_ALLOWED) {
+ return 0;
+ }
return ContentProvider.this.delete(uri, selection, selectionArgs);
}
@Override
- public int update(Uri uri, ContentValues values, String selection,
+ public int update(String callingPkg, Uri uri, ContentValues values, String selection,
String[] selectionArgs) {
- enforceWritePermission(uri);
+ if (enforceWritePermission(callingPkg, uri) != AppOpsManager.MODE_ALLOWED) {
+ return 0;
+ }
return ContentProvider.this.update(uri, values, selection, selectionArgs);
}
@Override
- public ParcelFileDescriptor openFile(Uri uri, String mode)
+ public ParcelFileDescriptor openFile(String callingPkg, Uri uri, String mode)
throws FileNotFoundException {
- if (mode != null && mode.startsWith("rw")) enforceWritePermission(uri);
- else enforceReadPermission(uri);
+ enforceFilePermission(callingPkg, uri, mode);
return ContentProvider.this.openFile(uri, mode);
}
@Override
- public AssetFileDescriptor openAssetFile(Uri uri, String mode)
+ public AssetFileDescriptor openAssetFile(String callingPkg, Uri uri, String mode)
throws FileNotFoundException {
- if (mode != null && mode.startsWith("rw")) enforceWritePermission(uri);
- else enforceReadPermission(uri);
+ enforceFilePermission(callingPkg, uri, mode);
return ContentProvider.this.openAssetFile(uri, mode);
}
@Override
- public Bundle call(String method, String arg, Bundle extras) {
+ public Bundle call(String callingPkg, String method, String arg, Bundle extras) {
return ContentProvider.this.call(method, arg, extras);
}
@@ -262,9 +280,9 @@ public abstract class ContentProvider implements ComponentCallbacks2 {
}
@Override
- public AssetFileDescriptor openTypedAssetFile(Uri uri, String mimeType, Bundle opts)
- throws FileNotFoundException {
- enforceReadPermission(uri);
+ public AssetFileDescriptor openTypedAssetFile(String callingPkg, Uri uri, String mimeType,
+ Bundle opts) throws FileNotFoundException {
+ enforceFilePermission(callingPkg, uri, "r");
return ContentProvider.this.openTypedAssetFile(uri, mimeType, opts);
}
@@ -273,7 +291,28 @@ public abstract class ContentProvider implements ComponentCallbacks2 {
return CancellationSignal.createTransport();
}
- private void enforceReadPermission(Uri uri) throws SecurityException {
+ private void enforceFilePermission(String callingPkg, Uri uri, String mode)
+ throws FileNotFoundException, SecurityException {
+ if (mode != null && mode.startsWith("rw")) {
+ if (enforceWritePermission(callingPkg, uri) != AppOpsManager.MODE_ALLOWED) {
+ throw new FileNotFoundException("App op not allowed");
+ }
+ } else {
+ if (enforceReadPermission(callingPkg, uri) != AppOpsManager.MODE_ALLOWED) {
+ throw new FileNotFoundException("App op not allowed");
+ }
+ }
+ }
+
+ private int enforceReadPermission(String callingPkg, Uri uri) throws SecurityException {
+ enforceReadPermissionInner(uri);
+ if (mAppOpsManager != null) {
+ return mAppOpsManager.noteOp(mReadOp, Binder.getCallingUid(), callingPkg);
+ }
+ return AppOpsManager.MODE_ALLOWED;
+ }
+
+ private void enforceReadPermissionInner(Uri uri) throws SecurityException {
final Context context = getContext();
final int pid = Binder.getCallingPid();
final int uid = Binder.getCallingUid();
@@ -334,7 +373,15 @@ public abstract class ContentProvider implements ComponentCallbacks2 {
+ ", uid=" + uid + failReason);
}
- private void enforceWritePermission(Uri uri) throws SecurityException {
+ private int enforceWritePermission(String callingPkg, Uri uri) throws SecurityException {
+ enforceWritePermissionInner(uri);
+ if (mAppOpsManager != null) {
+ return mAppOpsManager.noteOp(mWriteOp, Binder.getCallingUid(), callingPkg);
+ }
+ return AppOpsManager.MODE_ALLOWED;
+ }
+
+ private void enforceWritePermissionInner(Uri uri) throws SecurityException {
final Context context = getContext();
final int pid = Binder.getCallingPid();
final int uid = Binder.getCallingUid();
@@ -471,6 +518,14 @@ public abstract class ContentProvider implements ComponentCallbacks2 {
return mPathPermissions;
}
+ /** @hide */
+ public final void setAppOps(int readOp, int writeOp) {
+ mTransport.mAppOpsManager = (AppOpsManager)mContext.getSystemService(
+ Context.APP_OPS_SERVICE);
+ mTransport.mReadOp = readOp;
+ mTransport.mWriteOp = writeOp;
+ }
+
/**
* Implement this to initialize your content provider on startup.
* This method is called for all registered content providers on the
diff --git a/core/java/android/content/ContentProviderClient.java b/core/java/android/content/ContentProviderClient.java
index 204f963..8dffac7 100644
--- a/core/java/android/content/ContentProviderClient.java
+++ b/core/java/android/content/ContentProviderClient.java
@@ -45,6 +45,7 @@ import java.util.ArrayList;
public class ContentProviderClient {
private final IContentProvider mContentProvider;
private final ContentResolver mContentResolver;
+ private final String mPackageName;
private final boolean mStable;
private boolean mReleased;
@@ -55,6 +56,7 @@ public class ContentProviderClient {
IContentProvider contentProvider, boolean stable) {
mContentProvider = contentProvider;
mContentResolver = contentResolver;
+ mPackageName = contentResolver.mPackageName;
mStable = stable;
}
@@ -81,8 +83,8 @@ public class ContentProviderClient {
cancellationSignal.setRemote(remoteCancellationSignal);
}
try {
- return mContentProvider.query(url, projection, selection, selectionArgs, sortOrder,
- remoteCancellationSignal);
+ return mContentProvider.query(mPackageName, url, projection, selection, selectionArgs,
+ sortOrder, remoteCancellationSignal);
} catch (DeadObjectException e) {
if (!mStable) {
mContentResolver.unstableProviderDied(mContentProvider);
@@ -119,7 +121,7 @@ public class ContentProviderClient {
public Uri insert(Uri url, ContentValues initialValues)
throws RemoteException {
try {
- return mContentProvider.insert(url, initialValues);
+ return mContentProvider.insert(mPackageName, url, initialValues);
} catch (DeadObjectException e) {
if (!mStable) {
mContentResolver.unstableProviderDied(mContentProvider);
@@ -131,7 +133,7 @@ public class ContentProviderClient {
/** See {@link ContentProvider#bulkInsert ContentProvider.bulkInsert} */
public int bulkInsert(Uri url, ContentValues[] initialValues) throws RemoteException {
try {
- return mContentProvider.bulkInsert(url, initialValues);
+ return mContentProvider.bulkInsert(mPackageName, url, initialValues);
} catch (DeadObjectException e) {
if (!mStable) {
mContentResolver.unstableProviderDied(mContentProvider);
@@ -144,7 +146,7 @@ public class ContentProviderClient {
public int delete(Uri url, String selection, String[] selectionArgs)
throws RemoteException {
try {
- return mContentProvider.delete(url, selection, selectionArgs);
+ return mContentProvider.delete(mPackageName, url, selection, selectionArgs);
} catch (DeadObjectException e) {
if (!mStable) {
mContentResolver.unstableProviderDied(mContentProvider);
@@ -157,7 +159,7 @@ public class ContentProviderClient {
public int update(Uri url, ContentValues values, String selection,
String[] selectionArgs) throws RemoteException {
try {
- return mContentProvider.update(url, values, selection, selectionArgs);
+ return mContentProvider.update(mPackageName, url, values, selection, selectionArgs);
} catch (DeadObjectException e) {
if (!mStable) {
mContentResolver.unstableProviderDied(mContentProvider);
@@ -176,7 +178,7 @@ public class ContentProviderClient {
public ParcelFileDescriptor openFile(Uri url, String mode)
throws RemoteException, FileNotFoundException {
try {
- return mContentProvider.openFile(url, mode);
+ return mContentProvider.openFile(mPackageName, url, mode);
} catch (DeadObjectException e) {
if (!mStable) {
mContentResolver.unstableProviderDied(mContentProvider);
@@ -195,7 +197,7 @@ public class ContentProviderClient {
public AssetFileDescriptor openAssetFile(Uri url, String mode)
throws RemoteException, FileNotFoundException {
try {
- return mContentProvider.openAssetFile(url, mode);
+ return mContentProvider.openAssetFile(mPackageName, url, mode);
} catch (DeadObjectException e) {
if (!mStable) {
mContentResolver.unstableProviderDied(mContentProvider);
@@ -209,7 +211,7 @@ public class ContentProviderClient {
String mimeType, Bundle opts)
throws RemoteException, FileNotFoundException {
try {
- return mContentProvider.openTypedAssetFile(uri, mimeType, opts);
+ return mContentProvider.openTypedAssetFile(mPackageName, uri, mimeType, opts);
} catch (DeadObjectException e) {
if (!mStable) {
mContentResolver.unstableProviderDied(mContentProvider);
@@ -222,7 +224,7 @@ public class ContentProviderClient {
public ContentProviderResult[] applyBatch(ArrayList<ContentProviderOperation> operations)
throws RemoteException, OperationApplicationException {
try {
- return mContentProvider.applyBatch(operations);
+ return mContentProvider.applyBatch(mPackageName, operations);
} catch (DeadObjectException e) {
if (!mStable) {
mContentResolver.unstableProviderDied(mContentProvider);
@@ -235,7 +237,7 @@ public class ContentProviderClient {
public Bundle call(String method, String arg, Bundle extras)
throws RemoteException {
try {
- return mContentProvider.call(method, arg, extras);
+ return mContentProvider.call(mPackageName, method, arg, extras);
} catch (DeadObjectException e) {
if (!mStable) {
mContentResolver.unstableProviderDied(mContentProvider);
diff --git a/core/java/android/content/ContentProviderNative.java b/core/java/android/content/ContentProviderNative.java
index 384ba57..6f822c1 100644
--- a/core/java/android/content/ContentProviderNative.java
+++ b/core/java/android/content/ContentProviderNative.java
@@ -81,6 +81,7 @@ abstract public class ContentProviderNative extends Binder implements IContentPr
{
data.enforceInterface(IContentProvider.descriptor);
+ String callingPkg = data.readString();
Uri url = Uri.CREATOR.createFromParcel(data);
// String[] projection
@@ -110,8 +111,8 @@ abstract public class ContentProviderNative extends Binder implements IContentPr
ICancellationSignal cancellationSignal = ICancellationSignal.Stub.asInterface(
data.readStrongBinder());
- Cursor cursor = query(url, projection, selection, selectionArgs, sortOrder,
- cancellationSignal);
+ Cursor cursor = query(callingPkg, url, projection, selection, selectionArgs,
+ sortOrder, cancellationSignal);
if (cursor != null) {
try {
CursorToBulkCursorAdaptor adaptor = new CursorToBulkCursorAdaptor(
@@ -150,10 +151,11 @@ abstract public class ContentProviderNative extends Binder implements IContentPr
case INSERT_TRANSACTION:
{
data.enforceInterface(IContentProvider.descriptor);
+ String callingPkg = data.readString();
Uri url = Uri.CREATOR.createFromParcel(data);
ContentValues values = ContentValues.CREATOR.createFromParcel(data);
- Uri out = insert(url, values);
+ Uri out = insert(callingPkg, url, values);
reply.writeNoException();
Uri.writeToParcel(reply, out);
return true;
@@ -162,10 +164,11 @@ abstract public class ContentProviderNative extends Binder implements IContentPr
case BULK_INSERT_TRANSACTION:
{
data.enforceInterface(IContentProvider.descriptor);
+ String callingPkg = data.readString();
Uri url = Uri.CREATOR.createFromParcel(data);
ContentValues[] values = data.createTypedArray(ContentValues.CREATOR);
- int count = bulkInsert(url, values);
+ int count = bulkInsert(callingPkg, url, values);
reply.writeNoException();
reply.writeInt(count);
return true;
@@ -174,13 +177,14 @@ abstract public class ContentProviderNative extends Binder implements IContentPr
case APPLY_BATCH_TRANSACTION:
{
data.enforceInterface(IContentProvider.descriptor);
+ String callingPkg = data.readString();
final int numOperations = data.readInt();
final ArrayList<ContentProviderOperation> operations =
new ArrayList<ContentProviderOperation>(numOperations);
for (int i = 0; i < numOperations; i++) {
operations.add(i, ContentProviderOperation.CREATOR.createFromParcel(data));
}
- final ContentProviderResult[] results = applyBatch(operations);
+ final ContentProviderResult[] results = applyBatch(callingPkg, operations);
reply.writeNoException();
reply.writeTypedArray(results, 0);
return true;
@@ -189,11 +193,12 @@ abstract public class ContentProviderNative extends Binder implements IContentPr
case DELETE_TRANSACTION:
{
data.enforceInterface(IContentProvider.descriptor);
+ String callingPkg = data.readString();
Uri url = Uri.CREATOR.createFromParcel(data);
String selection = data.readString();
String[] selectionArgs = data.readStringArray();
- int count = delete(url, selection, selectionArgs);
+ int count = delete(callingPkg, url, selection, selectionArgs);
reply.writeNoException();
reply.writeInt(count);
@@ -203,12 +208,13 @@ abstract public class ContentProviderNative extends Binder implements IContentPr
case UPDATE_TRANSACTION:
{
data.enforceInterface(IContentProvider.descriptor);
+ String callingPkg = data.readString();
Uri url = Uri.CREATOR.createFromParcel(data);
ContentValues values = ContentValues.CREATOR.createFromParcel(data);
String selection = data.readString();
String[] selectionArgs = data.readStringArray();
- int count = update(url, values, selection, selectionArgs);
+ int count = update(callingPkg, url, values, selection, selectionArgs);
reply.writeNoException();
reply.writeInt(count);
@@ -218,11 +224,12 @@ abstract public class ContentProviderNative extends Binder implements IContentPr
case OPEN_FILE_TRANSACTION:
{
data.enforceInterface(IContentProvider.descriptor);
+ String callingPkg = data.readString();
Uri url = Uri.CREATOR.createFromParcel(data);
String mode = data.readString();
ParcelFileDescriptor fd;
- fd = openFile(url, mode);
+ fd = openFile(callingPkg, url, mode);
reply.writeNoException();
if (fd != null) {
reply.writeInt(1);
@@ -237,11 +244,12 @@ abstract public class ContentProviderNative extends Binder implements IContentPr
case OPEN_ASSET_FILE_TRANSACTION:
{
data.enforceInterface(IContentProvider.descriptor);
+ String callingPkg = data.readString();
Uri url = Uri.CREATOR.createFromParcel(data);
String mode = data.readString();
AssetFileDescriptor fd;
- fd = openAssetFile(url, mode);
+ fd = openAssetFile(callingPkg, url, mode);
reply.writeNoException();
if (fd != null) {
reply.writeInt(1);
@@ -257,11 +265,12 @@ abstract public class ContentProviderNative extends Binder implements IContentPr
{
data.enforceInterface(IContentProvider.descriptor);
+ String callingPkg = data.readString();
String method = data.readString();
String stringArg = data.readString();
Bundle args = data.readBundle();
- Bundle responseBundle = call(method, stringArg, args);
+ Bundle responseBundle = call(callingPkg, method, stringArg, args);
reply.writeNoException();
reply.writeBundle(responseBundle);
@@ -283,12 +292,13 @@ abstract public class ContentProviderNative extends Binder implements IContentPr
case OPEN_TYPED_ASSET_FILE_TRANSACTION:
{
data.enforceInterface(IContentProvider.descriptor);
+ String callingPkg = data.readString();
Uri url = Uri.CREATOR.createFromParcel(data);
String mimeType = data.readString();
Bundle opts = data.readBundle();
AssetFileDescriptor fd;
- fd = openTypedAssetFile(url, mimeType, opts);
+ fd = openTypedAssetFile(callingPkg, url, mimeType, opts);
reply.writeNoException();
if (fd != null) {
reply.writeInt(1);
@@ -337,7 +347,7 @@ final class ContentProviderProxy implements IContentProvider
return mRemote;
}
- public Cursor query(Uri url, String[] projection, String selection,
+ public Cursor query(String callingPkg, Uri url, String[] projection, String selection,
String[] selectionArgs, String sortOrder, ICancellationSignal cancellationSignal)
throws RemoteException {
BulkCursorToCursorAdaptor adaptor = new BulkCursorToCursorAdaptor();
@@ -346,6 +356,7 @@ final class ContentProviderProxy implements IContentProvider
try {
data.writeInterfaceToken(IContentProvider.descriptor);
+ data.writeString(callingPkg);
url.writeToParcel(data, 0);
int length = 0;
if (projection != null) {
@@ -413,13 +424,14 @@ final class ContentProviderProxy implements IContentProvider
}
}
- public Uri insert(Uri url, ContentValues values) throws RemoteException
+ public Uri insert(String callingPkg, Uri url, ContentValues values) throws RemoteException
{
Parcel data = Parcel.obtain();
Parcel reply = Parcel.obtain();
try {
data.writeInterfaceToken(IContentProvider.descriptor);
+ data.writeString(callingPkg);
url.writeToParcel(data, 0);
values.writeToParcel(data, 0);
@@ -434,12 +446,13 @@ final class ContentProviderProxy implements IContentProvider
}
}
- public int bulkInsert(Uri url, ContentValues[] values) throws RemoteException {
+ public int bulkInsert(String callingPkg, Uri url, ContentValues[] values) throws RemoteException {
Parcel data = Parcel.obtain();
Parcel reply = Parcel.obtain();
try {
data.writeInterfaceToken(IContentProvider.descriptor);
+ data.writeString(callingPkg);
url.writeToParcel(data, 0);
data.writeTypedArray(values, 0);
@@ -454,12 +467,14 @@ final class ContentProviderProxy implements IContentProvider
}
}
- public ContentProviderResult[] applyBatch(ArrayList<ContentProviderOperation> operations)
- throws RemoteException, OperationApplicationException {
+ public ContentProviderResult[] applyBatch(String callingPkg,
+ ArrayList<ContentProviderOperation> operations)
+ throws RemoteException, OperationApplicationException {
Parcel data = Parcel.obtain();
Parcel reply = Parcel.obtain();
try {
data.writeInterfaceToken(IContentProvider.descriptor);
+ data.writeString(callingPkg);
data.writeInt(operations.size());
for (ContentProviderOperation operation : operations) {
operation.writeToParcel(data, 0);
@@ -476,13 +491,14 @@ final class ContentProviderProxy implements IContentProvider
}
}
- public int delete(Uri url, String selection, String[] selectionArgs)
+ public int delete(String callingPkg, Uri url, String selection, String[] selectionArgs)
throws RemoteException {
Parcel data = Parcel.obtain();
Parcel reply = Parcel.obtain();
try {
data.writeInterfaceToken(IContentProvider.descriptor);
+ data.writeString(callingPkg);
url.writeToParcel(data, 0);
data.writeString(selection);
data.writeStringArray(selectionArgs);
@@ -498,13 +514,14 @@ final class ContentProviderProxy implements IContentProvider
}
}
- public int update(Uri url, ContentValues values, String selection,
+ public int update(String callingPkg, Uri url, ContentValues values, String selection,
String[] selectionArgs) throws RemoteException {
Parcel data = Parcel.obtain();
Parcel reply = Parcel.obtain();
try {
data.writeInterfaceToken(IContentProvider.descriptor);
+ data.writeString(callingPkg);
url.writeToParcel(data, 0);
values.writeToParcel(data, 0);
data.writeString(selection);
@@ -521,13 +538,14 @@ final class ContentProviderProxy implements IContentProvider
}
}
- public ParcelFileDescriptor openFile(Uri url, String mode)
+ public ParcelFileDescriptor openFile(String callingPkg, Uri url, String mode)
throws RemoteException, FileNotFoundException {
Parcel data = Parcel.obtain();
Parcel reply = Parcel.obtain();
try {
data.writeInterfaceToken(IContentProvider.descriptor);
+ data.writeString(callingPkg);
url.writeToParcel(data, 0);
data.writeString(mode);
@@ -543,13 +561,14 @@ final class ContentProviderProxy implements IContentProvider
}
}
- public AssetFileDescriptor openAssetFile(Uri url, String mode)
+ public AssetFileDescriptor openAssetFile(String callingPkg, Uri url, String mode)
throws RemoteException, FileNotFoundException {
Parcel data = Parcel.obtain();
Parcel reply = Parcel.obtain();
try {
data.writeInterfaceToken(IContentProvider.descriptor);
+ data.writeString(callingPkg);
url.writeToParcel(data, 0);
data.writeString(mode);
@@ -566,13 +585,14 @@ final class ContentProviderProxy implements IContentProvider
}
}
- public Bundle call(String method, String request, Bundle args)
+ public Bundle call(String callingPkg, String method, String request, Bundle args)
throws RemoteException {
Parcel data = Parcel.obtain();
Parcel reply = Parcel.obtain();
try {
data.writeInterfaceToken(IContentProvider.descriptor);
+ data.writeString(callingPkg);
data.writeString(method);
data.writeString(request);
data.writeBundle(args);
@@ -609,13 +629,14 @@ final class ContentProviderProxy implements IContentProvider
}
}
- public AssetFileDescriptor openTypedAssetFile(Uri url, String mimeType, Bundle opts)
- throws RemoteException, FileNotFoundException {
+ public AssetFileDescriptor openTypedAssetFile(String callingPkg, Uri url, String mimeType,
+ Bundle opts) throws RemoteException, FileNotFoundException {
Parcel data = Parcel.obtain();
Parcel reply = Parcel.obtain();
try {
data.writeInterfaceToken(IContentProvider.descriptor);
+ data.writeString(callingPkg);
url.writeToParcel(data, 0);
data.writeString(mimeType);
data.writeBundle(opts);
diff --git a/core/java/android/content/ContentResolver.java b/core/java/android/content/ContentResolver.java
index 86bf8c2..51c9aa5 100644
--- a/core/java/android/content/ContentResolver.java
+++ b/core/java/android/content/ContentResolver.java
@@ -207,6 +207,7 @@ public abstract class ContentResolver {
public ContentResolver(Context context) {
mContext = context;
+ mPackageName = context.getPackageName();
}
/** @hide */
@@ -392,7 +393,7 @@ public abstract class ContentResolver {
cancellationSignal.setRemote(remoteCancellationSignal);
}
try {
- qCursor = unstableProvider.query(uri, projection,
+ qCursor = unstableProvider.query(mPackageName, uri, projection,
selection, selectionArgs, sortOrder, remoteCancellationSignal);
} catch (DeadObjectException e) {
// The remote process has died... but we only hold an unstable
@@ -403,7 +404,7 @@ public abstract class ContentResolver {
if (stableProvider == null) {
return null;
}
- qCursor = stableProvider.query(uri, projection,
+ qCursor = stableProvider.query(mPackageName, uri, projection,
selection, selectionArgs, sortOrder, remoteCancellationSignal);
}
if (qCursor == null) {
@@ -651,7 +652,7 @@ public abstract class ContentResolver {
try {
try {
- fd = unstableProvider.openAssetFile(uri, mode);
+ fd = unstableProvider.openAssetFile(mPackageName, uri, mode);
if (fd == null) {
// The provider will be released by the finally{} clause
return null;
@@ -665,7 +666,7 @@ public abstract class ContentResolver {
if (stableProvider == null) {
throw new FileNotFoundException("No content provider: " + uri);
}
- fd = stableProvider.openAssetFile(uri, mode);
+ fd = stableProvider.openAssetFile(mPackageName, uri, mode);
if (fd == null) {
// The provider will be released by the finally{} clause
return null;
@@ -743,7 +744,7 @@ public abstract class ContentResolver {
try {
try {
- fd = unstableProvider.openTypedAssetFile(uri, mimeType, opts);
+ fd = unstableProvider.openTypedAssetFile(mPackageName, uri, mimeType, opts);
if (fd == null) {
// The provider will be released by the finally{} clause
return null;
@@ -757,7 +758,7 @@ public abstract class ContentResolver {
if (stableProvider == null) {
throw new FileNotFoundException("No content provider: " + uri);
}
- fd = stableProvider.openTypedAssetFile(uri, mimeType, opts);
+ fd = stableProvider.openTypedAssetFile(mPackageName, uri, mimeType, opts);
if (fd == null) {
// The provider will be released by the finally{} clause
return null;
@@ -892,7 +893,7 @@ public abstract class ContentResolver {
}
try {
long startTime = SystemClock.uptimeMillis();
- Uri createdRow = provider.insert(url, values);
+ Uri createdRow = provider.insert(mPackageName, url, values);
long durationMillis = SystemClock.uptimeMillis() - startTime;
maybeLogUpdateToEventLog(durationMillis, url, "insert", null /* where */);
return createdRow;
@@ -953,7 +954,7 @@ public abstract class ContentResolver {
}
try {
long startTime = SystemClock.uptimeMillis();
- int rowsCreated = provider.bulkInsert(url, values);
+ int rowsCreated = provider.bulkInsert(mPackageName, url, values);
long durationMillis = SystemClock.uptimeMillis() - startTime;
maybeLogUpdateToEventLog(durationMillis, url, "bulkinsert", null /* where */);
return rowsCreated;
@@ -984,7 +985,7 @@ public abstract class ContentResolver {
}
try {
long startTime = SystemClock.uptimeMillis();
- int rowsDeleted = provider.delete(url, where, selectionArgs);
+ int rowsDeleted = provider.delete(mPackageName, url, where, selectionArgs);
long durationMillis = SystemClock.uptimeMillis() - startTime;
maybeLogUpdateToEventLog(durationMillis, url, "delete", where);
return rowsDeleted;
@@ -1018,7 +1019,7 @@ public abstract class ContentResolver {
}
try {
long startTime = SystemClock.uptimeMillis();
- int rowsUpdated = provider.update(uri, values, where, selectionArgs);
+ int rowsUpdated = provider.update(mPackageName, uri, values, where, selectionArgs);
long durationMillis = SystemClock.uptimeMillis() - startTime;
maybeLogUpdateToEventLog(durationMillis, uri, "update", where);
return rowsUpdated;
@@ -1057,7 +1058,7 @@ public abstract class ContentResolver {
throw new IllegalArgumentException("Unknown URI " + uri);
}
try {
- return provider.call(method, arg, extras);
+ return provider.call(mPackageName, method, arg, extras);
} catch (RemoteException e) {
// Arbitrary and not worth documenting, as Activity
// Manager will kill this process shortly anyway.
@@ -1955,7 +1956,13 @@ public abstract class ContentResolver {
return sContentService;
}
+ /** @hide */
+ public String getPackageName() {
+ return mPackageName;
+ }
+
private static IContentService sContentService;
private final Context mContext;
+ final String mPackageName;
private static final String TAG = "ContentResolver";
}
diff --git a/core/java/android/content/IContentProvider.java b/core/java/android/content/IContentProvider.java
index eeba1e0..62b79f0 100644
--- a/core/java/android/content/IContentProvider.java
+++ b/core/java/android/content/IContentProvider.java
@@ -34,30 +34,33 @@ import java.util.ArrayList;
* @hide
*/
public interface IContentProvider extends IInterface {
- public Cursor query(Uri url, String[] projection, String selection,
+ public Cursor query(String callingPkg, Uri url, String[] projection, String selection,
String[] selectionArgs, String sortOrder, ICancellationSignal cancellationSignal)
throws RemoteException;
public String getType(Uri url) throws RemoteException;
- public Uri insert(Uri url, ContentValues initialValues)
+ public Uri insert(String callingPkg, Uri url, ContentValues initialValues)
throws RemoteException;
- public int bulkInsert(Uri url, ContentValues[] initialValues) throws RemoteException;
- public int delete(Uri url, String selection, String[] selectionArgs)
+ public int bulkInsert(String callingPkg, Uri url, ContentValues[] initialValues)
throws RemoteException;
- public int update(Uri url, ContentValues values, String selection,
+ public int delete(String callingPkg, Uri url, String selection, String[] selectionArgs)
+ throws RemoteException;
+ public int update(String callingPkg, Uri url, ContentValues values, String selection,
String[] selectionArgs) throws RemoteException;
- public ParcelFileDescriptor openFile(Uri url, String mode)
+ public ParcelFileDescriptor openFile(String callingPkg, Uri url, String mode)
throws RemoteException, FileNotFoundException;
- public AssetFileDescriptor openAssetFile(Uri url, String mode)
+ public AssetFileDescriptor openAssetFile(String callingPkg, Uri url, String mode)
throws RemoteException, FileNotFoundException;
- public ContentProviderResult[] applyBatch(ArrayList<ContentProviderOperation> operations)
- throws RemoteException, OperationApplicationException;
- public Bundle call(String method, String arg, Bundle extras) throws RemoteException;
+ public ContentProviderResult[] applyBatch(String callingPkg,
+ ArrayList<ContentProviderOperation> operations)
+ throws RemoteException, OperationApplicationException;
+ public Bundle call(String callingPkg, String method, String arg, Bundle extras)
+ throws RemoteException;
public ICancellationSignal createCancellationSignal() throws RemoteException;
// Data interchange.
public String[] getStreamTypes(Uri url, String mimeTypeFilter) throws RemoteException;
- public AssetFileDescriptor openTypedAssetFile(Uri url, String mimeType, Bundle opts)
- throws RemoteException, FileNotFoundException;
+ public AssetFileDescriptor openTypedAssetFile(String callingPkg, Uri url, String mimeType,
+ Bundle opts) throws RemoteException, FileNotFoundException;
/* IPC constants */
static final String descriptor = "android.content.IContentProvider";
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 441214c..3d850cf 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -456,6 +456,18 @@ public final class Settings {
"android.settings.APPLICATION_DETAILS_SETTINGS";
/**
+ * @hide
+ * Activity Action: Show the "app ops" settings screen.
+ * <p>
+ * Input: Nothing.
+ * <p>
+ * Output: Nothing.
+ */
+ @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
+ public static final String ACTION_APP_OPS_SETTINGS =
+ "android.settings.APP_OPS_SETTINGS";
+
+ /**
* Activity Action: Show settings for system update functionality.
* <p>
* In some cases, a matching Activity may not exist, so ensure you
@@ -774,7 +786,7 @@ public final class Settings {
arg.putString(Settings.NameValueTable.VALUE, value);
arg.putInt(CALL_METHOD_USER_KEY, userHandle);
IContentProvider cp = lazyGetProvider(cr);
- cp.call(mCallSetCommand, name, arg);
+ cp.call(cr.getPackageName(), mCallSetCommand, name, arg);
} catch (RemoteException e) {
Log.w(TAG, "Can't set key " + name + " in " + mUri, e);
return false;
@@ -821,7 +833,7 @@ public final class Settings {
args = new Bundle();
args.putInt(CALL_METHOD_USER_KEY, userHandle);
}
- Bundle b = cp.call(mCallGetCommand, name, args);
+ Bundle b = cp.call(cr.getPackageName(), mCallGetCommand, name, args);
if (b != null) {
String value = b.getPairValue();
// Don't update our cache for reads of other users' data
@@ -846,7 +858,7 @@ public final class Settings {
Cursor c = null;
try {
- c = cp.query(mUri, SELECT_VALUE, NAME_EQ_PLACEHOLDER,
+ c = cp.query(cr.getPackageName(), mUri, SELECT_VALUE, NAME_EQ_PLACEHOLDER,
new String[]{name}, null, null);
if (c == null) {
Log.w(TAG, "Can't get key " + name + " from " + mUri);
diff --git a/core/java/com/android/internal/app/IAppOpsService.aidl b/core/java/com/android/internal/app/IAppOpsService.aidl
index c934587..827dba6 100644
--- a/core/java/com/android/internal/app/IAppOpsService.aidl
+++ b/core/java/com/android/internal/app/IAppOpsService.aidl
@@ -16,10 +16,12 @@
package com.android.internal.app;
+import android.app.AppOpsManager;
+
interface IAppOpsService {
+ List<AppOpsManager.PackageOps> getPackagesForOps(in int[] ops);
+ int checkOperation(int code, int uid, String packageName);
int noteOperation(int code, int uid, String packageName);
int startOperation(int code, int uid, String packageName);
void finishOperation(int code, int uid, String packageName);
- int noteTimedOperation(int code, int uid, String packageName, int duration);
- void earlyFinishOperation(int code, int uid, String packageName);
}
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index e357255..a69870b 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -1606,6 +1606,13 @@
android:description="@string/permdesc_updateBatteryStats"
android:protectionLevel="signature|system" />
+ <!-- @hide Allows an application to collect battery statistics -->
+ <permission android:name="android.permission.GET_APP_OPS_STATS"
+ android:permissionGroup="android.permission-group.SYSTEM_TOOLS"
+ android:label="@string/permlab_getAppOpsStats"
+ android:description="@string/permdesc_getAppOpsStats"
+ android:protectionLevel="signature|system|development" />
+
<!-- Allows an application to update application operation statistics. Not for
use by third party apps. @hide -->
<permission android:name="android.permission.UPDATE_APP_OPS_STATS"
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index 6a93860..fa26089 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -843,6 +843,12 @@
collected battery statistics. Not for use by normal apps.</string>
<!-- [CHAR LIMIT=NONE] Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
+ <string name="permlab_getAppOpsStats">retrieve app ops statistics</string>
+ <!-- [CHAR LIMIT=NONE] Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
+ <string name="permdesc_getAppOpsStats">Allows the app to retrieve
+ collected application operation statistics. Not for use by normal apps.</string>
+
+ <!-- [CHAR LIMIT=NONE] Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
<string name="permlab_updateAppOpsStats">modify app ops statistics</string>
<!-- [CHAR LIMIT=NONE] Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
<string name="permdesc_updateAppOpsStats">Allows the app to modify
diff --git a/media/java/android/media/MediaInserter.java b/media/java/android/media/MediaInserter.java
index 7fcbffa..41b369d 100644
--- a/media/java/android/media/MediaInserter.java
+++ b/media/java/android/media/MediaInserter.java
@@ -37,11 +37,13 @@ public class MediaInserter {
private final HashMap<Uri, List<ContentValues>> mPriorityRowMap =
new HashMap<Uri, List<ContentValues>>();
- private IContentProvider mProvider;
- private int mBufferSizePerUri;
+ private final IContentProvider mProvider;
+ private final String mPackageName;
+ private final int mBufferSizePerUri;
- public MediaInserter(IContentProvider provider, int bufferSizePerUri) {
+ public MediaInserter(IContentProvider provider, String packageName, int bufferSizePerUri) {
mProvider = provider;
+ mPackageName = packageName;
mBufferSizePerUri = bufferSizePerUri;
}
@@ -88,7 +90,7 @@ public class MediaInserter {
if (!list.isEmpty()) {
ContentValues[] valuesArray = new ContentValues[list.size()];
valuesArray = list.toArray(valuesArray);
- mProvider.bulkInsert(tableUri, valuesArray);
+ mProvider.bulkInsert(mPackageName, tableUri, valuesArray);
list.clear();
}
}
diff --git a/media/java/android/media/MediaScanner.java b/media/java/android/media/MediaScanner.java
index 7768a61..619e71c 100644
--- a/media/java/android/media/MediaScanner.java
+++ b/media/java/android/media/MediaScanner.java
@@ -303,6 +303,7 @@ public class MediaScanner
private int mNativeContext;
private Context mContext;
+ private String mPackageName;
private IContentProvider mMediaProvider;
private Uri mAudioUri;
private Uri mVideoUri;
@@ -388,6 +389,7 @@ public class MediaScanner
public MediaScanner(Context c) {
native_setup();
mContext = c;
+ mPackageName = c.getPackageName();
mBitmapOptions.inSampleSize = 1;
mBitmapOptions.inJustDecodeBounds = true;
@@ -961,7 +963,7 @@ public class MediaScanner
if (inserter != null) {
inserter.flushAll();
}
- result = mMediaProvider.insert(tableUri, values);
+ result = mMediaProvider.insert(mPackageName, tableUri, values);
} else if (entry.mFormat == MtpConstants.FORMAT_ASSOCIATION) {
inserter.insertwithPriority(tableUri, values);
} else {
@@ -993,7 +995,7 @@ public class MediaScanner
}
values.put(FileColumns.MEDIA_TYPE, mediaType);
}
- mMediaProvider.update(result, values, null, null);
+ mMediaProvider.update(mPackageName, result, values, null, null);
}
if(needToSetSettings) {
@@ -1082,7 +1084,8 @@ public class MediaScanner
// filesystem is mounted and unmounted while the scanner is running).
Uri.Builder builder = mFilesUri.buildUpon();
builder.appendQueryParameter(MediaStore.PARAM_DELETE_DATA, "false");
- MediaBulkDeleter deleter = new MediaBulkDeleter(mMediaProvider, builder.build());
+ MediaBulkDeleter deleter = new MediaBulkDeleter(mMediaProvider, mPackageName,
+ builder.build());
// Build the list of files from the content provider
try {
@@ -1101,7 +1104,7 @@ public class MediaScanner
c.close();
c = null;
}
- c = mMediaProvider.query(limitUri, FILES_PRESCAN_PROJECTION,
+ c = mMediaProvider.query(mPackageName, limitUri, FILES_PRESCAN_PROJECTION,
where, selectionArgs, MediaStore.Files.FileColumns._ID, null);
if (c == null) {
break;
@@ -1142,7 +1145,8 @@ public class MediaScanner
if (path.toLowerCase(Locale.US).endsWith("/.nomedia")) {
deleter.flush();
String parent = new File(path).getParent();
- mMediaProvider.call(MediaStore.UNHIDE_CALL, parent, null);
+ mMediaProvider.call(mPackageName, MediaStore.UNHIDE_CALL,
+ parent, null);
}
}
}
@@ -1160,7 +1164,7 @@ public class MediaScanner
// compute original size of images
mOriginalCount = 0;
- c = mMediaProvider.query(mImagesUri, ID_PROJECTION, null, null, null, null);
+ c = mMediaProvider.query(mPackageName, mImagesUri, ID_PROJECTION, null, null, null, null);
if (c != null) {
mOriginalCount = c.getCount();
c.close();
@@ -1191,6 +1195,7 @@ public class MediaScanner
try {
Cursor c = mMediaProvider.query(
+ mPackageName,
mThumbsUri,
new String [] { "_data" },
null,
@@ -1225,11 +1230,13 @@ public class MediaScanner
static class MediaBulkDeleter {
StringBuilder whereClause = new StringBuilder();
ArrayList<String> whereArgs = new ArrayList<String>(100);
- IContentProvider mProvider;
- Uri mBaseUri;
+ final IContentProvider mProvider;
+ final String mPackageName;
+ final Uri mBaseUri;
- public MediaBulkDeleter(IContentProvider provider, Uri baseUri) {
+ public MediaBulkDeleter(IContentProvider provider, String packageName, Uri baseUri) {
mProvider = provider;
+ mPackageName = packageName;
mBaseUri = baseUri;
}
@@ -1248,7 +1255,8 @@ public class MediaScanner
if (size > 0) {
String [] foo = new String [size];
foo = whereArgs.toArray(foo);
- int numrows = mProvider.delete(mBaseUri, MediaStore.MediaColumns._ID + " IN (" +
+ int numrows = mProvider.delete(mPackageName, mBaseUri,
+ MediaStore.MediaColumns._ID + " IN (" +
whereClause.toString() + ")", foo);
//Log.i("@@@@@@@@@", "rows deleted: " + numrows);
whereClause.setLength(0);
@@ -1301,7 +1309,7 @@ public class MediaScanner
if (ENABLE_BULK_INSERTS) {
// create MediaInserter for bulk inserts
- mMediaInserter = new MediaInserter(mMediaProvider, 500);
+ mMediaInserter = new MediaInserter(mMediaProvider, mPackageName, 500);
}
for (int i = 0; i < directories.length; i++) {
@@ -1433,8 +1441,8 @@ public class MediaScanner
values.put(Files.FileColumns.DATE_MODIFIED, lastModifiedSeconds);
try {
String[] whereArgs = new String[] { Integer.toString(objectHandle) };
- mMediaProvider.update(Files.getMtpObjectsUri(volumeName), values, "_id=?",
- whereArgs);
+ mMediaProvider.update(mPackageName, Files.getMtpObjectsUri(volumeName), values,
+ "_id=?", whereArgs);
} catch (RemoteException e) {
Log.e(TAG, "RemoteException in scanMtpFile", e);
}
@@ -1450,8 +1458,8 @@ public class MediaScanner
FileEntry entry = makeEntryFor(path);
if (entry != null) {
- fileList = mMediaProvider.query(mFilesUri, FILES_PRESCAN_PROJECTION,
- null, null, null, null);
+ fileList = mMediaProvider.query(mPackageName, mFilesUri,
+ FILES_PRESCAN_PROJECTION, null, null, null, null);
processPlayList(entry, fileList);
}
} else {
@@ -1480,7 +1488,7 @@ public class MediaScanner
try {
where = Files.FileColumns.DATA + "=?";
selectionArgs = new String[] { path };
- c = mMediaProvider.query(mFilesUriNoNotify, FILES_PRESCAN_PROJECTION,
+ c = mMediaProvider.query(mPackageName, mFilesUriNoNotify, FILES_PRESCAN_PROJECTION,
where, selectionArgs, null, null);
if (c.moveToFirst()) {
long rowId = c.getLong(FILES_PRESCAN_ID_COLUMN_INDEX);
@@ -1592,7 +1600,7 @@ public class MediaScanner
values.clear();
values.put(MediaStore.Audio.Playlists.Members.PLAY_ORDER, Integer.valueOf(index));
values.put(MediaStore.Audio.Playlists.Members.AUDIO_ID, Long.valueOf(entry.bestmatchid));
- mMediaProvider.insert(playlistUri, values);
+ mMediaProvider.insert(mPackageName, playlistUri, values);
index++;
} catch (RemoteException e) {
Log.e(TAG, "RemoteException in MediaScanner.processCachedPlaylist()", e);
@@ -1757,16 +1765,16 @@ public class MediaScanner
if (rowId == 0) {
values.put(MediaStore.Audio.Playlists.DATA, path);
- uri = mMediaProvider.insert(mPlaylistsUri, values);
+ uri = mMediaProvider.insert(mPackageName, mPlaylistsUri, values);
rowId = ContentUris.parseId(uri);
membersUri = Uri.withAppendedPath(uri, Playlists.Members.CONTENT_DIRECTORY);
} else {
uri = ContentUris.withAppendedId(mPlaylistsUri, rowId);
- mMediaProvider.update(uri, values, null, null);
+ mMediaProvider.update(mPackageName, uri, values, null, null);
// delete members of existing playlist
membersUri = Uri.withAppendedPath(uri, Playlists.Members.CONTENT_DIRECTORY);
- mMediaProvider.delete(membersUri, null, null);
+ mMediaProvider.delete(mPackageName, membersUri, null, null);
}
String playListDirectory = path.substring(0, lastSlash + 1);
@@ -1788,7 +1796,7 @@ public class MediaScanner
try {
// use the files uri and projection because we need the format column,
// but restrict the query to just audio files
- fileList = mMediaProvider.query(mFilesUri, FILES_PRESCAN_PROJECTION,
+ fileList = mMediaProvider.query(mPackageName, mFilesUri, FILES_PRESCAN_PROJECTION,
"media_type=2", null, null, null);
while (iterator.hasNext()) {
FileEntry entry = iterator.next();
diff --git a/media/java/android/mtp/MtpDatabase.java b/media/java/android/mtp/MtpDatabase.java
index 487585e..ea12803 100644
--- a/media/java/android/mtp/MtpDatabase.java
+++ b/media/java/android/mtp/MtpDatabase.java
@@ -48,6 +48,7 @@ public class MtpDatabase {
private static final String TAG = "MtpDatabase";
private final Context mContext;
+ private final String mPackageName;
private final IContentProvider mMediaProvider;
private final String mVolumeName;
private final Uri mObjectsUri;
@@ -123,6 +124,7 @@ public class MtpDatabase {
native_setup();
mContext = context;
+ mPackageName = context.getPackageName();
mMediaProvider = context.getContentResolver().acquireProvider("media");
mVolumeName = volumeName;
mMediaStoragePath = storagePath;
@@ -263,7 +265,7 @@ public class MtpDatabase {
if (path != null) {
Cursor c = null;
try {
- c = mMediaProvider.query(mObjectsUri, ID_PROJECTION, PATH_WHERE,
+ c = mMediaProvider.query(mPackageName, mObjectsUri, ID_PROJECTION, PATH_WHERE,
new String[] { path }, null, null);
if (c != null && c.getCount() > 0) {
Log.w(TAG, "file already exists in beginSendObject: " + path);
@@ -288,7 +290,7 @@ public class MtpDatabase {
values.put(Files.FileColumns.DATE_MODIFIED, modified);
try {
- Uri uri = mMediaProvider.insert(mObjectsUri, values);
+ Uri uri = mMediaProvider.insert(mPackageName, mObjectsUri, values);
if (uri != null) {
return Integer.parseInt(uri.getPathSegments().get(2));
} else {
@@ -323,7 +325,8 @@ public class MtpDatabase {
values.put(Files.FileColumns.DATE_MODIFIED, System.currentTimeMillis() / 1000);
values.put(MediaColumns.MEDIA_SCANNER_NEW_OBJECT_ID, handle);
try {
- Uri uri = mMediaProvider.insert(Audio.Playlists.EXTERNAL_CONTENT_URI, values);
+ Uri uri = mMediaProvider.insert(mPackageName,
+ Audio.Playlists.EXTERNAL_CONTENT_URI, values);
} catch (RemoteException e) {
Log.e(TAG, "RemoteException in endSendObject", e);
}
@@ -431,7 +434,8 @@ public class MtpDatabase {
}
}
- return mMediaProvider.query(mObjectsUri, ID_PROJECTION, where, whereArgs, null, null);
+ return mMediaProvider.query(mPackageName, mObjectsUri, ID_PROJECTION, where,
+ whereArgs, null, null);
}
private int[] getObjectList(int storageID, int format, int parent) {
@@ -676,14 +680,16 @@ public class MtpDatabase {
propertyGroup = mPropertyGroupsByFormat.get(format);
if (propertyGroup == null) {
int[] propertyList = getSupportedObjectProperties(format);
- propertyGroup = new MtpPropertyGroup(this, mMediaProvider, mVolumeName, propertyList);
+ propertyGroup = new MtpPropertyGroup(this, mMediaProvider, mPackageName,
+ mVolumeName, propertyList);
mPropertyGroupsByFormat.put(new Integer(format), propertyGroup);
}
} else {
propertyGroup = mPropertyGroupsByProperty.get(property);
if (propertyGroup == null) {
int[] propertyList = new int[] { (int)property };
- propertyGroup = new MtpPropertyGroup(this, mMediaProvider, mVolumeName, propertyList);
+ propertyGroup = new MtpPropertyGroup(this, mMediaProvider, mPackageName,
+ mVolumeName, propertyList);
mPropertyGroupsByProperty.put(new Integer((int)property), propertyGroup);
}
}
@@ -698,7 +704,8 @@ public class MtpDatabase {
String path = null;
String[] whereArgs = new String[] { Integer.toString(handle) };
try {
- c = mMediaProvider.query(mObjectsUri, PATH_PROJECTION, ID_WHERE, whereArgs, null, null);
+ c = mMediaProvider.query(mPackageName, mObjectsUri, PATH_PROJECTION, ID_WHERE,
+ whereArgs, null, null);
if (c != null && c.moveToNext()) {
path = c.getString(1);
}
@@ -740,7 +747,7 @@ public class MtpDatabase {
try {
// note - we are relying on a special case in MediaProvider.update() to update
// the paths for all children in the case where this is a directory.
- updated = mMediaProvider.update(mObjectsUri, values, ID_WHERE, whereArgs);
+ updated = mMediaProvider.update(mPackageName, mObjectsUri, values, ID_WHERE, whereArgs);
} catch (RemoteException e) {
Log.e(TAG, "RemoteException in mMediaProvider.update", e);
}
@@ -757,7 +764,7 @@ public class MtpDatabase {
if (oldFile.getName().startsWith(".") && !newPath.startsWith(".")) {
// directory was unhidden
try {
- mMediaProvider.call(MediaStore.UNHIDE_CALL, newPath, null);
+ mMediaProvider.call(mPackageName, MediaStore.UNHIDE_CALL, newPath, null);
} catch (RemoteException e) {
Log.e(TAG, "failed to unhide/rescan for " + newPath);
}
@@ -767,7 +774,7 @@ public class MtpDatabase {
if (oldFile.getName().toLowerCase(Locale.US).equals(".nomedia")
&& !newPath.toLowerCase(Locale.US).equals(".nomedia")) {
try {
- mMediaProvider.call(MediaStore.UNHIDE_CALL, oldFile.getParent(), null);
+ mMediaProvider.call(mPackageName, MediaStore.UNHIDE_CALL, oldFile.getParent(), null);
} catch (RemoteException e) {
Log.e(TAG, "failed to unhide/rescan for " + newPath);
}
@@ -836,7 +843,7 @@ public class MtpDatabase {
char[] outName, long[] outModified) {
Cursor c = null;
try {
- c = mMediaProvider.query(mObjectsUri, OBJECT_INFO_PROJECTION,
+ c = mMediaProvider.query(mPackageName, mObjectsUri, OBJECT_INFO_PROJECTION,
ID_WHERE, new String[] { Integer.toString(handle) }, null, null);
if (c != null && c.moveToNext()) {
outStorageFormatParent[0] = c.getInt(1);
@@ -878,7 +885,7 @@ public class MtpDatabase {
}
Cursor c = null;
try {
- c = mMediaProvider.query(mObjectsUri, PATH_FORMAT_PROJECTION,
+ c = mMediaProvider.query(mPackageName, mObjectsUri, PATH_FORMAT_PROJECTION,
ID_WHERE, new String[] { Integer.toString(handle) }, null, null);
if (c != null && c.moveToNext()) {
String path = c.getString(1);
@@ -909,7 +916,7 @@ public class MtpDatabase {
Cursor c = null;
try {
- c = mMediaProvider.query(mObjectsUri, PATH_FORMAT_PROJECTION,
+ c = mMediaProvider.query(mPackageName, mObjectsUri, PATH_FORMAT_PROJECTION,
ID_WHERE, new String[] { Integer.toString(handle) }, null, null);
if (c != null && c.moveToNext()) {
// don't convert to media path here, since we will be matching
@@ -932,7 +939,7 @@ public class MtpDatabase {
if (format == MtpConstants.FORMAT_ASSOCIATION) {
// recursive case - delete all children first
Uri uri = Files.getMtpObjectsUri(mVolumeName);
- int count = mMediaProvider.delete(uri,
+ int count = mMediaProvider.delete(mPackageName, uri,
// the 'like' makes it use the index, the 'lower()' makes it correct
// when the path contains sqlite wildcard characters
"_data LIKE ?1 AND lower(substr(_data,1,?2))=lower(?3)",
@@ -940,12 +947,12 @@ public class MtpDatabase {
}
Uri uri = Files.getMtpObjectsUri(mVolumeName, handle);
- if (mMediaProvider.delete(uri, null, null) > 0) {
+ if (mMediaProvider.delete(mPackageName, uri, null, null) > 0) {
if (format != MtpConstants.FORMAT_ASSOCIATION
&& path.toLowerCase(Locale.US).endsWith("/.nomedia")) {
try {
String parentPath = path.substring(0, path.lastIndexOf("/"));
- mMediaProvider.call(MediaStore.UNHIDE_CALL, parentPath, null);
+ mMediaProvider.call(mPackageName, MediaStore.UNHIDE_CALL, parentPath, null);
} catch (RemoteException e) {
Log.e(TAG, "failed to unhide/rescan for " + path);
}
@@ -968,7 +975,7 @@ public class MtpDatabase {
Uri uri = Files.getMtpReferencesUri(mVolumeName, handle);
Cursor c = null;
try {
- c = mMediaProvider.query(uri, ID_PROJECTION, null, null, null, null);
+ c = mMediaProvider.query(mPackageName, uri, ID_PROJECTION, null, null, null, null);
if (c == null) {
return null;
}
@@ -1002,7 +1009,7 @@ public class MtpDatabase {
valuesList[i] = values;
}
try {
- if (mMediaProvider.bulkInsert(uri, valuesList) > 0) {
+ if (mMediaProvider.bulkInsert(mPackageName, uri, valuesList) > 0) {
return MtpConstants.RESPONSE_OK;
}
} catch (RemoteException e) {
diff --git a/media/java/android/mtp/MtpPropertyGroup.java b/media/java/android/mtp/MtpPropertyGroup.java
index dab5454..48da40f 100644
--- a/media/java/android/mtp/MtpPropertyGroup.java
+++ b/media/java/android/mtp/MtpPropertyGroup.java
@@ -50,6 +50,7 @@ class MtpPropertyGroup {
private final MtpDatabase mDatabase;
private final IContentProvider mProvider;
+ private final String mPackageName;
private final String mVolumeName;
private final Uri mUri;
@@ -65,10 +66,11 @@ class MtpPropertyGroup {
private static final String PARENT_WHERE = Files.FileColumns.PARENT + "=?";
private static final String PARENT_FORMAT_WHERE = PARENT_WHERE + " AND " + FORMAT_WHERE;
// constructs a property group for a list of properties
- public MtpPropertyGroup(MtpDatabase database, IContentProvider provider, String volume,
- int[] properties) {
+ public MtpPropertyGroup(MtpDatabase database, IContentProvider provider, String packageName,
+ String volume, int[] properties) {
mDatabase = database;
mProvider = provider;
+ mPackageName = packageName;
mVolumeName = volume;
mUri = Files.getMtpObjectsUri(volume);
@@ -189,7 +191,7 @@ class MtpPropertyGroup {
Cursor c = null;
try {
// for now we are only reading properties from the "objects" table
- c = mProvider.query(mUri,
+ c = mProvider.query(mPackageName, mUri,
new String [] { Files.FileColumns._ID, column },
ID_WHERE, new String[] { Integer.toString(id) }, null, null);
if (c != null && c.moveToNext()) {
@@ -209,7 +211,7 @@ class MtpPropertyGroup {
private String queryAudio(int id, String column) {
Cursor c = null;
try {
- c = mProvider.query(Audio.Media.getContentUri(mVolumeName),
+ c = mProvider.query(mPackageName, Audio.Media.getContentUri(mVolumeName),
new String [] { Files.FileColumns._ID, column },
ID_WHERE, new String[] { Integer.toString(id) }, null, null);
if (c != null && c.moveToNext()) {
@@ -230,7 +232,7 @@ class MtpPropertyGroup {
Cursor c = null;
try {
Uri uri = Audio.Genres.getContentUriForAudioId(mVolumeName, id);
- c = mProvider.query(uri,
+ c = mProvider.query(mPackageName, uri,
new String [] { Files.FileColumns._ID, Audio.GenresColumns.NAME },
null, null, null, null);
if (c != null && c.moveToNext()) {
@@ -252,7 +254,7 @@ class MtpPropertyGroup {
Cursor c = null;
try {
// for now we are only reading properties from the "objects" table
- c = mProvider.query(mUri,
+ c = mProvider.query(mPackageName, mUri,
new String [] { Files.FileColumns._ID, column },
ID_WHERE, new String[] { Integer.toString(id) }, null, null);
if (c != null && c.moveToNext()) {
@@ -323,7 +325,7 @@ class MtpPropertyGroup {
try {
// don't query if not necessary
if (depth > 0 || handle == 0xFFFFFFFF || mColumns.length > 1) {
- c = mProvider.query(mUri, mColumns, where, whereArgs, null, null);
+ c = mProvider.query(mPackageName, mUri, mColumns, where, whereArgs, null, null);
if (c == null) {
return new MtpPropertyList(0, MtpConstants.RESPONSE_INVALID_OBJECT_HANDLE);
}
diff --git a/services/java/com/android/server/AppOpsService.java b/services/java/com/android/server/AppOpsService.java
index 539194c..aff994c 100644
--- a/services/java/com/android/server/AppOpsService.java
+++ b/services/java/com/android/server/AppOpsService.java
@@ -18,15 +18,22 @@ package com.android.server;
import java.io.File;
import java.io.FileDescriptor;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.IOException;
import java.io.PrintWriter;
+import java.util.ArrayList;
import java.util.HashMap;
+import java.util.List;
import android.app.AppOpsManager;
import android.content.Context;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
+import android.os.AsyncTask;
import android.os.Binder;
-import android.os.Environment;
+import android.os.Handler;
import android.os.Process;
import android.os.ServiceManager;
import android.os.UserHandle;
@@ -34,23 +41,53 @@ import android.util.AtomicFile;
import android.util.Slog;
import android.util.SparseArray;
import android.util.TimeUtils;
+import android.util.Xml;
import com.android.internal.app.IAppOpsService;
+import com.android.internal.util.FastXmlSerializer;
+import com.android.internal.util.XmlUtils;
+
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+import org.xmlpull.v1.XmlSerializer;
public class AppOpsService extends IAppOpsService.Stub {
static final String TAG = "AppOps";
+ static final boolean DEBUG = false;
+
+ // Write at most every 30 minutes.
+ static final long WRITE_DELAY = DEBUG ? 1000 : 30*60*1000;
Context mContext;
final AtomicFile mFile;
+ final Handler mHandler;
+
+ boolean mWriteScheduled;
+ final Runnable mWriteRunner = new Runnable() {
+ public void run() {
+ synchronized (AppOpsService.this) {
+ mWriteScheduled = false;
+ AsyncTask<Void, Void, Void> task = new AsyncTask<Void, Void, Void>() {
+ @Override protected Void doInBackground(Void... params) {
+ writeState();
+ return null;
+ }
+ };
+ task.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, (Void[])null);
+ }
+ }
+ };
final SparseArray<HashMap<String, Ops>> mUidOps
= new SparseArray<HashMap<String, Ops>>();
final static class Ops extends SparseArray<Op> {
public final String packageName;
+ public final int uid;
- public Ops(String _packageName) {
+ public Ops(String _packageName, int _uid) {
packageName = _packageName;
+ uid = _uid;
}
}
@@ -58,14 +95,17 @@ public class AppOpsService extends IAppOpsService.Stub {
public final int op;
public int duration;
public long time;
+ public int nesting;
public Op(int _op) {
op = _op;
}
}
- public AppOpsService() {
- mFile = new AtomicFile(new File(Environment.getSecureDataDirectory(), "appops.xml"));
+ public AppOpsService(File storagePath) {
+ mFile = new AtomicFile(storagePath);
+ mHandler = new Handler();
+ readState();
}
public void publish(Context context) {
@@ -75,94 +115,126 @@ public class AppOpsService extends IAppOpsService.Stub {
public void shutdown() {
Slog.w(TAG, "Writing app ops before shutdown...");
+ boolean doWrite = false;
+ synchronized (this) {
+ if (mWriteScheduled) {
+ mWriteScheduled = false;
+ doWrite = true;
+ }
+ }
+ if (doWrite) {
+ writeState();
+ }
}
@Override
- public int noteOperation(int code, int uid, String packageName) {
- uid = handleIncomingUid(uid);
+ public List<AppOpsManager.PackageOps> getPackagesForOps(int[] ops) {
+ mContext.enforcePermission(android.Manifest.permission.GET_APP_OPS_STATS,
+ Binder.getCallingPid(), Binder.getCallingUid(), null);
+ ArrayList<AppOpsManager.PackageOps> res = null;
synchronized (this) {
- Op op = getOpLocked(code, uid, packageName);
- if (op == null) {
- 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);
+ for (int i=0; i<mUidOps.size(); i++) {
+ HashMap<String, Ops> packages = mUidOps.valueAt(i);
+ for (Ops pkgOps : packages.values()) {
+ ArrayList<AppOpsManager.OpEntry> resOps = null;
+ if (ops == null) {
+ 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));
+ }
+ } else {
+ for (int j=0; j<ops.length; j++) {
+ Op curOp = pkgOps.get(ops[j]);
+ if (curOp != null) {
+ if (resOps == null) {
+ resOps = new ArrayList<AppOpsManager.OpEntry>();
+ }
+ resOps.add(new AppOpsManager.OpEntry(curOp.op, curOp.time,
+ curOp.duration));
+ }
+ }
+ }
+ if (resOps != null) {
+ if (res == null) {
+ res = new ArrayList<AppOpsManager.PackageOps>();
+ }
+ AppOpsManager.PackageOps resPackage = new AppOpsManager.PackageOps(
+ pkgOps.packageName, pkgOps.uid, resOps);
+ res.add(resPackage);
+ }
+ }
}
- op.time = System.currentTimeMillis();
- op.duration = 0;
}
- return AppOpsManager.MODE_ALLOWED;
+ return res;
}
@Override
- public int startOperation(int code, int uid, String packageName) {
+ public int checkOperation(int code, int uid, String packageName) {
uid = handleIncomingUid(uid);
synchronized (this) {
- Op op = getOpLocked(code, uid, packageName);
+ Op op = getOpLocked(code, uid, packageName, false);
if (op == null) {
- return AppOpsManager.MODE_IGNORED;
- }
- if (op.duration == -1) {
- Slog.w(TAG, "Starting op not finished: uid " + uid + " pkg " + packageName
- + " code " + code + " time=" + op.time + " duration=" + op.duration);
+ return AppOpsManager.MODE_ALLOWED;
}
- op.time = System.currentTimeMillis();
- op.duration = -1;
}
return AppOpsManager.MODE_ALLOWED;
}
@Override
- public void finishOperation(int code, int uid, String packageName) {
+ public int noteOperation(int code, int uid, String packageName) {
uid = handleIncomingUid(uid);
synchronized (this) {
- Op op = getOpLocked(code, uid, packageName);
+ Op op = getOpLocked(code, uid, packageName, true);
if (op == null) {
- return;
+ return AppOpsManager.MODE_IGNORED;
}
- if (op.duration != -1) {
- Slog.w(TAG, "Ignoring finishing op not started: uid " + uid + " pkg " + packageName
+ if (op.duration == -1) {
+ Slog.w(TAG, "Noting op not finished: uid " + uid + " pkg " + packageName
+ " code " + code + " time=" + op.time + " duration=" + op.duration);
- return;
}
- op.duration = (int)(System.currentTimeMillis() - op.time);
+ op.time = System.currentTimeMillis();
+ op.duration = 0;
}
+ return AppOpsManager.MODE_ALLOWED;
}
@Override
- public int noteTimedOperation(int code, int uid, String packageName, int duration) {
+ public int startOperation(int code, int uid, String packageName) {
uid = handleIncomingUid(uid);
synchronized (this) {
- Op op = getOpLocked(code, uid, packageName);
+ Op op = getOpLocked(code, uid, packageName, true);
if (op == null) {
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);
+ if (op.nesting == 0) {
+ op.time = System.currentTimeMillis();
+ op.duration = -1;
}
- op.time = System.currentTimeMillis();
- op.duration = duration;
+ op.nesting++;
}
return AppOpsManager.MODE_ALLOWED;
}
@Override
- public void earlyFinishOperation(int code, int uid, String packageName) {
+ public void finishOperation(int code, int uid, String packageName) {
uid = handleIncomingUid(uid);
synchronized (this) {
- Op op = getOpLocked(code, uid, packageName);
+ Op op = getOpLocked(code, uid, packageName, true);
if (op == null) {
return;
}
- if (op.duration != -1) {
- Slog.w(TAG, "Noting timed op not finished: uid " + uid + " pkg " + packageName
- + " code " + code + " time=" + op.time + " duration=" + op.duration);
- }
- int newDuration = (int)(System.currentTimeMillis() - op.time);
- if (newDuration < op.duration) {
- op.duration = newDuration;
+ if (op.nesting <= 1) {
+ if (op.nesting == 1) {
+ op.duration = (int)(System.currentTimeMillis() - op.time);
+ } else {
+ Slog.w(TAG, "Finishing op nesting under-run: uid " + uid + " pkg " + packageName
+ + " code " + code + " time=" + op.time + " duration=" + op.duration
+ + " nesting=" + op.nesting);
+ }
+ } else {
+ op.nesting--;
}
}
}
@@ -179,14 +251,20 @@ public class AppOpsService extends IAppOpsService.Stub {
return uid;
}
- private Op getOpLocked(int code, int uid, String packageName) {
+ private Op getOpLocked(int code, int uid, String packageName, boolean edit) {
HashMap<String, Ops> pkgOps = mUidOps.get(uid);
if (pkgOps == null) {
+ if (!edit) {
+ return null;
+ }
pkgOps = new HashMap<String, Ops>();
mUidOps.put(uid, pkgOps);
}
Ops ops = pkgOps.get(packageName);
if (ops == null) {
+ if (!edit) {
+ return null;
+ }
// This is the first time we have seen this package name under this uid,
// so let's make sure it is valid.
final long ident = Binder.clearCallingIdentity();
@@ -207,17 +285,205 @@ public class AppOpsService extends IAppOpsService.Stub {
} finally {
Binder.restoreCallingIdentity(ident);
}
- ops = new Ops(packageName);
+ ops = new Ops(packageName, uid);
pkgOps.put(packageName, ops);
}
Op op = ops.get(code);
if (op == null) {
+ if (!edit) {
+ return null;
+ }
op = new Op(code);
ops.put(code, op);
}
+ if (edit && !mWriteScheduled) {
+ mWriteScheduled = true;
+ mHandler.postDelayed(mWriteRunner, WRITE_DELAY);
+ }
return op;
}
+ void readState() {
+ synchronized (mFile) {
+ synchronized (this) {
+ FileInputStream stream;
+ try {
+ stream = mFile.openRead();
+ } catch (FileNotFoundException e) {
+ Slog.i(TAG, "No existing app ops " + mFile.getBaseFile() + "; starting empty");
+ return;
+ }
+ boolean success = false;
+ try {
+ XmlPullParser parser = Xml.newPullParser();
+ parser.setInput(stream, null);
+ int type;
+ while ((type = parser.next()) != XmlPullParser.START_TAG
+ && type != XmlPullParser.END_DOCUMENT) {
+ ;
+ }
+
+ if (type != XmlPullParser.START_TAG) {
+ throw new IllegalStateException("no start tag found");
+ }
+
+ int outerDepth = parser.getDepth();
+ while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
+ && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
+ if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
+ continue;
+ }
+
+ String tagName = parser.getName();
+ if (tagName.equals("pkg")) {
+ readPackage(parser);
+ } else {
+ Slog.w(TAG, "Unknown element under <app-ops>: "
+ + parser.getName());
+ XmlUtils.skipCurrentTag(parser);
+ }
+ }
+ success = true;
+ } catch (IllegalStateException e) {
+ Slog.w(TAG, "Failed parsing " + e);
+ } catch (NullPointerException e) {
+ Slog.w(TAG, "Failed parsing " + e);
+ } catch (NumberFormatException e) {
+ Slog.w(TAG, "Failed parsing " + e);
+ } catch (XmlPullParserException e) {
+ Slog.w(TAG, "Failed parsing " + e);
+ } catch (IOException e) {
+ Slog.w(TAG, "Failed parsing " + e);
+ } catch (IndexOutOfBoundsException e) {
+ Slog.w(TAG, "Failed parsing " + e);
+ } finally {
+ if (!success) {
+ mUidOps.clear();
+ }
+ try {
+ stream.close();
+ } catch (IOException e) {
+ }
+ }
+ }
+ }
+ }
+
+ void readPackage(XmlPullParser parser) throws NumberFormatException,
+ XmlPullParserException, IOException {
+ String pkgName = parser.getAttributeValue(null, "n");
+ int outerDepth = parser.getDepth();
+ int type;
+ while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
+ && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
+ if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
+ continue;
+ }
+
+ String tagName = parser.getName();
+ if (tagName.equals("uid")) {
+ readUid(parser, pkgName);
+ } else {
+ Slog.w(TAG, "Unknown element under <pkg>: "
+ + parser.getName());
+ XmlUtils.skipCurrentTag(parser);
+ }
+ }
+ }
+
+ void readUid(XmlPullParser parser, String pkgName) throws NumberFormatException,
+ XmlPullParserException, IOException {
+ int uid = Integer.parseInt(parser.getAttributeValue(null, "n"));
+ int outerDepth = parser.getDepth();
+ int type;
+ while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
+ && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
+ if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
+ continue;
+ }
+
+ 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"));
+ HashMap<String, Ops> pkgOps = mUidOps.get(uid);
+ if (pkgOps == null) {
+ pkgOps = new HashMap<String, Ops>();
+ mUidOps.put(uid, pkgOps);
+ }
+ Ops ops = pkgOps.get(pkgName);
+ if (ops == null) {
+ ops = new Ops(pkgName, uid);
+ pkgOps.put(pkgName, ops);
+ }
+ ops.put(op.op, op);
+ } else {
+ Slog.w(TAG, "Unknown element under <pkg>: "
+ + parser.getName());
+ XmlUtils.skipCurrentTag(parser);
+ }
+ }
+ }
+
+ void writeState() {
+ synchronized (mFile) {
+ List<AppOpsManager.PackageOps> allOps = getPackagesForOps(null);
+
+ FileOutputStream stream;
+ try {
+ stream = mFile.startWrite();
+ } catch (IOException e) {
+ Slog.w(TAG, "Failed to write state: " + e);
+ return;
+ }
+
+ try {
+ XmlSerializer out = new FastXmlSerializer();
+ out.setOutput(stream, "utf-8");
+ out.startDocument(null, true);
+ out.startTag(null, "app-ops");
+
+ if (allOps != null) {
+ String lastPkg = null;
+ for (int i=0; i<allOps.size(); i++) {
+ AppOpsManager.PackageOps pkg = allOps.get(i);
+ if (!pkg.getPackageName().equals(lastPkg)) {
+ if (lastPkg != null) {
+ out.endTag(null, "pkg");
+ }
+ lastPkg = pkg.getPackageName();
+ out.startTag(null, "pkg");
+ out.attribute(null, "n", lastPkg);
+ }
+ out.startTag(null, "uid");
+ out.attribute(null, "n", Integer.toString(pkg.getUid()));
+ List<AppOpsManager.OpEntry> ops = pkg.getOps();
+ for (int j=0; j<ops.size(); j++) {
+ 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()));
+ out.endTag(null, "op");
+ }
+ out.endTag(null, "uid");
+ }
+ if (lastPkg != null) {
+ out.endTag(null, "pkg");
+ }
+ }
+
+ out.endTag(null, "app-ops");
+ out.endDocument();
+ mFile.finishWrite(stream);
+ } catch (IOException e) {
+ Slog.w(TAG, "Failed to write state, restoring backup.", e);
+ mFile.failWrite(stream);
+ }
+ }
+ }
+
@Override
protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
diff --git a/services/java/com/android/server/LocationManagerService.java b/services/java/com/android/server/LocationManagerService.java
index 946ed78..b351fc2 100644
--- a/services/java/com/android/server/LocationManagerService.java
+++ b/services/java/com/android/server/LocationManagerService.java
@@ -529,8 +529,7 @@ public class LocationManagerService extends ILocationManager.Stub {
}
public boolean callLocationChangedLocked(Location location) {
- if (mAppOps.noteOpNoThrow(AppOpsManager.OP_LOCATION, mUid, mPackageName)
- != AppOpsManager.MODE_ALLOWED) {
+ if (!reportLocationAccessNoThrow(mUid, mPackageName, mAllowedResolutionLevel)) {
return true;
}
if (mListener != null) {
@@ -803,6 +802,36 @@ public class LocationManagerService extends ILocationManager.Stub {
}
}
+ boolean reportLocationAccessNoThrow(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;
+ }
+ if (mAppOps.noteOpNoThrow(op, uid, packageName) != AppOpsManager.MODE_ALLOWED) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ 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;
+ }
+ if (mAppOps.checkOp(op, uid, packageName) != AppOpsManager.MODE_ALLOWED) {
+ return false;
+ }
+ }
+ return true;
+ }
+
/**
* Returns all providers by name, including passive, but excluding
* fused, also including ones that are not permitted to
@@ -1199,7 +1228,7 @@ public class LocationManagerService extends ILocationManager.Stub {
try {
// We don't check for MODE_IGNORED here; we will do that when we go to deliver
// a location.
- mAppOps.noteOp(AppOpsManager.OP_LOCATION, uid, packageName);
+ checkLocationAccess(uid, packageName, allowedResolutionLevel);
Receiver recevier = checkListenerOrIntent(listener, intent, pid, uid, packageName);
synchronized (mLock) {
@@ -1311,8 +1340,7 @@ public class LocationManagerService extends ILocationManager.Stub {
final int uid = Binder.getCallingUid();
final long identity = Binder.clearCallingIdentity();
try {
- if (mAppOps.noteOp(AppOpsManager.OP_LOCATION, uid, packageName)
- != AppOpsManager.MODE_ALLOWED) {
+ if (!reportLocationAccessNoThrow(uid, packageName, allowedResolutionLevel)) {
return null;
}
@@ -1403,14 +1431,14 @@ public class LocationManagerService extends ILocationManager.Stub {
if (mGpsStatusProvider == null) {
return false;
}
- checkResolutionLevelIsSufficientForProviderUse(getCallerAllowedResolutionLevel(),
+ int allowedResolutionLevel = getCallerAllowedResolutionLevel();
+ checkResolutionLevelIsSufficientForProviderUse(allowedResolutionLevel,
LocationManager.GPS_PROVIDER);
final int uid = Binder.getCallingUid();
final long ident = Binder.clearCallingIdentity();
try {
- if (mAppOps.noteOp(AppOpsManager.OP_LOCATION, uid, packageName)
- != AppOpsManager.MODE_ALLOWED) {
+ if (checkLocationAccess(uid, packageName, allowedResolutionLevel)) {
return false;
}
} finally {
diff --git a/services/java/com/android/server/am/ActivityManagerService.java b/services/java/com/android/server/am/ActivityManagerService.java
index 8297988..d8e199b 100644
--- a/services/java/com/android/server/am/ActivityManagerService.java
+++ b/services/java/com/android/server/am/ActivityManagerService.java
@@ -1623,7 +1623,7 @@ public final class ActivityManagerService extends ActivityManagerNative
mUsageStatsService = new UsageStatsService(new File(
systemDir, "usagestats").toString());
- mAppOpsService = new AppOpsService();
+ mAppOpsService = new AppOpsService(new File(systemDir, "appops.xml"));
mHeadless = "1".equals(SystemProperties.get("ro.config.headless", "0"));
// User 0 is the first and only user that runs at boot.
@@ -7105,7 +7105,7 @@ public final class ActivityManagerService extends ActivityManagerNative
sCallerIdentity.set(new Identity(
Binder.getCallingPid(), Binder.getCallingUid()));
try {
- pfd = cph.provider.openFile(uri, "r");
+ pfd = cph.provider.openFile(null, uri, "r");
} catch (FileNotFoundException e) {
// do nothing; pfd will be returned null
} finally {
diff --git a/test-runner/src/android/test/mock/MockContentProvider.java b/test-runner/src/android/test/mock/MockContentProvider.java
index 1e41416..373f24a 100644
--- a/test-runner/src/android/test/mock/MockContentProvider.java
+++ b/test-runner/src/android/test/mock/MockContentProvider.java
@@ -53,18 +53,20 @@ public class MockContentProvider extends ContentProvider {
*/
private class InversionIContentProvider implements IContentProvider {
@Override
- public ContentProviderResult[] applyBatch(ArrayList<ContentProviderOperation> operations)
+ public ContentProviderResult[] applyBatch(String callingPackage,
+ ArrayList<ContentProviderOperation> operations)
throws RemoteException, OperationApplicationException {
return MockContentProvider.this.applyBatch(operations);
}
@Override
- public int bulkInsert(Uri url, ContentValues[] initialValues) throws RemoteException {
+ public int bulkInsert(String callingPackage, Uri url, ContentValues[] initialValues)
+ throws RemoteException {
return MockContentProvider.this.bulkInsert(url, initialValues);
}
@Override
- public int delete(Uri url, String selection, String[] selectionArgs)
+ public int delete(String callingPackage, Uri url, String selection, String[] selectionArgs)
throws RemoteException {
return MockContentProvider.this.delete(url, selection, selectionArgs);
}
@@ -75,37 +77,39 @@ public class MockContentProvider extends ContentProvider {
}
@Override
- public Uri insert(Uri url, ContentValues initialValues) throws RemoteException {
+ public Uri insert(String callingPackage, Uri url, ContentValues initialValues)
+ throws RemoteException {
return MockContentProvider.this.insert(url, initialValues);
}
@Override
- public AssetFileDescriptor openAssetFile(Uri url, String mode) throws RemoteException,
- FileNotFoundException {
+ public AssetFileDescriptor openAssetFile(String callingPackage, Uri url, String mode)
+ throws RemoteException, FileNotFoundException {
return MockContentProvider.this.openAssetFile(url, mode);
}
@Override
- public ParcelFileDescriptor openFile(Uri url, String mode) throws RemoteException,
- FileNotFoundException {
+ public ParcelFileDescriptor openFile(String callingPackage, Uri url, String mode)
+ throws RemoteException, FileNotFoundException {
return MockContentProvider.this.openFile(url, mode);
}
@Override
- public Cursor query(Uri url, String[] projection, String selection, String[] selectionArgs,
+ public Cursor query(String callingPackage, Uri url, String[] projection, String selection,
+ String[] selectionArgs,
String sortOrder, ICancellationSignal cancellationSignal) throws RemoteException {
return MockContentProvider.this.query(url, projection, selection,
selectionArgs, sortOrder);
}
@Override
- public int update(Uri url, ContentValues values, String selection, String[] selectionArgs)
- throws RemoteException {
+ public int update(String callingPackage, Uri url, ContentValues values, String selection,
+ String[] selectionArgs) throws RemoteException {
return MockContentProvider.this.update(url, values, selection, selectionArgs);
}
@Override
- public Bundle call(String method, String request, Bundle args)
+ public Bundle call(String callingPackage, String method, String request, Bundle args)
throws RemoteException {
return MockContentProvider.this.call(method, request, args);
}
@@ -121,7 +125,8 @@ public class MockContentProvider extends ContentProvider {
}
@Override
- public AssetFileDescriptor openTypedAssetFile(Uri url, String mimeType, Bundle opts)
+ public AssetFileDescriptor openTypedAssetFile(String callingPackage, Uri url,
+ String mimeType, Bundle opts)
throws RemoteException, FileNotFoundException {
return MockContentProvider.this.openTypedAssetFile(url, mimeType, opts);
}
diff --git a/test-runner/src/android/test/mock/MockIContentProvider.java b/test-runner/src/android/test/mock/MockIContentProvider.java
index 9fcfc22..2b4fce6 100644
--- a/test-runner/src/android/test/mock/MockIContentProvider.java
+++ b/test-runner/src/android/test/mock/MockIContentProvider.java
@@ -41,12 +41,12 @@ import java.util.ArrayList;
* @hide - @hide because this exposes bulkQuery() and call(), which must also be hidden.
*/
public class MockIContentProvider implements IContentProvider {
- public int bulkInsert(Uri url, ContentValues[] initialValues) {
+ public int bulkInsert(String callingPackage, Uri url, ContentValues[] initialValues) {
throw new UnsupportedOperationException("unimplemented mock method");
}
@SuppressWarnings("unused")
- public int delete(Uri url, String selection, String[] selectionArgs)
+ public int delete(String callingPackage, Uri url, String selection, String[] selectionArgs)
throws RemoteException {
throw new UnsupportedOperationException("unimplemented mock method");
}
@@ -56,23 +56,26 @@ public class MockIContentProvider implements IContentProvider {
}
@SuppressWarnings("unused")
- public Uri insert(Uri url, ContentValues initialValues) throws RemoteException {
+ public Uri insert(String callingPackage, Uri url, ContentValues initialValues)
+ throws RemoteException {
throw new UnsupportedOperationException("unimplemented mock method");
}
- public ParcelFileDescriptor openFile(Uri url, String mode) {
+ public ParcelFileDescriptor openFile(String callingPackage, Uri url, String mode) {
throw new UnsupportedOperationException("unimplemented mock method");
}
- public AssetFileDescriptor openAssetFile(Uri uri, String mode) {
+ public AssetFileDescriptor openAssetFile(String callingPackage, Uri uri, String mode) {
throw new UnsupportedOperationException("unimplemented mock method");
}
- public ContentProviderResult[] applyBatch(ArrayList<ContentProviderOperation> operations) {
+ public ContentProviderResult[] applyBatch(String callingPackage,
+ ArrayList<ContentProviderOperation> operations) {
throw new UnsupportedOperationException("unimplemented mock method");
}
- public Cursor query(Uri url, String[] projection, String selection, String[] selectionArgs,
+ public Cursor query(String callingPackage, Uri url, String[] projection, String selection,
+ String[] selectionArgs,
String sortOrder, ICancellationSignal cancellationSignal) {
throw new UnsupportedOperationException("unimplemented mock method");
}
@@ -82,12 +85,12 @@ public class MockIContentProvider implements IContentProvider {
throw new UnsupportedOperationException("unimplemented mock method");
}
- public int update(Uri url, ContentValues values, String selection, String[] selectionArgs)
- throws RemoteException {
+ public int update(String callingPackage, Uri url, ContentValues values, String selection,
+ String[] selectionArgs) throws RemoteException {
throw new UnsupportedOperationException("unimplemented mock method");
}
- public Bundle call(String method, String request, Bundle args)
+ public Bundle call(String callingPackage, String method, String request, Bundle args)
throws RemoteException {
throw new UnsupportedOperationException("unimplemented mock method");
}
@@ -100,8 +103,8 @@ public class MockIContentProvider implements IContentProvider {
throw new UnsupportedOperationException("unimplemented mock method");
}
- public AssetFileDescriptor openTypedAssetFile(Uri url, String mimeType, Bundle opts)
- throws RemoteException, FileNotFoundException {
+ public AssetFileDescriptor openTypedAssetFile(String callingPackage, Uri url, String mimeType,
+ Bundle opts) throws RemoteException, FileNotFoundException {
throw new UnsupportedOperationException("unimplemented mock method");
}
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContentProvider.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContentProvider.java
index f770ccc..4aea38f 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContentProvider.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContentProvider.java
@@ -40,26 +40,30 @@ import java.util.ArrayList;
*/
public final class BridgeContentProvider implements IContentProvider {
@Override
- public ContentProviderResult[] applyBatch(ArrayList<ContentProviderOperation> arg0)
+ public ContentProviderResult[] applyBatch(String callingPackage,
+ ArrayList<ContentProviderOperation> arg0)
throws RemoteException, OperationApplicationException {
// TODO Auto-generated method stub
return null;
}
@Override
- public int bulkInsert(Uri arg0, ContentValues[] arg1) throws RemoteException {
+ public int bulkInsert(String callingPackage, Uri arg0, ContentValues[] arg1)
+ throws RemoteException {
// TODO Auto-generated method stub
return 0;
}
@Override
- public Bundle call(String arg0, String arg1, Bundle arg2) throws RemoteException {
+ public Bundle call(String callingPackage, String arg0, String arg1, Bundle arg2)
+ throws RemoteException {
// TODO Auto-generated method stub
return null;
}
@Override
- public int delete(Uri arg0, String arg1, String[] arg2) throws RemoteException {
+ public int delete(String callingPackage, Uri arg0, String arg1, String[] arg2)
+ throws RemoteException {
// TODO Auto-generated method stub
return 0;
}
@@ -71,35 +75,35 @@ public final class BridgeContentProvider implements IContentProvider {
}
@Override
- public Uri insert(Uri arg0, ContentValues arg1) throws RemoteException {
+ public Uri insert(String callingPackage, Uri arg0, ContentValues arg1) throws RemoteException {
// TODO Auto-generated method stub
return null;
}
@Override
- public AssetFileDescriptor openAssetFile(Uri arg0, String arg1) throws RemoteException,
- FileNotFoundException {
+ public AssetFileDescriptor openAssetFile(String callingPackage, Uri arg0, String arg1)
+ throws RemoteException, FileNotFoundException {
// TODO Auto-generated method stub
return null;
}
@Override
- public ParcelFileDescriptor openFile(Uri arg0, String arg1) throws RemoteException,
- FileNotFoundException {
+ public ParcelFileDescriptor openFile(String callingPackage, Uri arg0, String arg1)
+ throws RemoteException, FileNotFoundException {
// TODO Auto-generated method stub
return null;
}
@Override
- public Cursor query(Uri arg0, String[] arg1, String arg2, String[] arg3, String arg4,
- ICancellationSignal arg5) throws RemoteException {
+ public Cursor query(String callingPackage, Uri arg0, String[] arg1, String arg2, String[] arg3,
+ String arg4, ICancellationSignal arg5) throws RemoteException {
// TODO Auto-generated method stub
return null;
}
@Override
- public int update(Uri arg0, ContentValues arg1, String arg2, String[] arg3)
- throws RemoteException {
+ public int update(String callingPackage, Uri arg0, ContentValues arg1, String arg2,
+ String[] arg3) throws RemoteException {
// TODO Auto-generated method stub
return 0;
}
@@ -117,8 +121,8 @@ public final class BridgeContentProvider implements IContentProvider {
}
@Override
- public AssetFileDescriptor openTypedAssetFile(Uri arg0, String arg1, Bundle arg2)
- throws RemoteException, FileNotFoundException {
+ public AssetFileDescriptor openTypedAssetFile(String callingPackage, Uri arg0, String arg1,
+ Bundle arg2) throws RemoteException, FileNotFoundException {
// TODO Auto-generated method stub
return null;
}