summaryrefslogtreecommitdiff
path: root/core/java/android/content/ContentProvider.java
diff options
context:
space:
mode:
Diffstat (limited to 'core/java/android/content/ContentProvider.java')
-rw-r--r--core/java/android/content/ContentProvider.java428
1 files changed, 397 insertions, 31 deletions
diff --git a/core/java/android/content/ContentProvider.java b/core/java/android/content/ContentProvider.java
index cf627d7131ca..a9d055988862 100644
--- a/core/java/android/content/ContentProvider.java
+++ b/core/java/android/content/ContentProvider.java
@@ -16,11 +16,9 @@
package android.content;
-import static android.content.pm.PackageManager.GET_PROVIDERS;
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;
import android.content.res.AssetFileDescriptor;
@@ -36,7 +34,6 @@ import android.os.ICancellationSignal;
import android.os.OperationCanceledException;
import android.os.ParcelFileDescriptor;
import android.os.Process;
-import android.os.RemoteException;
import android.os.UserHandle;
import android.util.Log;
@@ -104,6 +101,8 @@ public abstract class ContentProvider implements ComponentCallbacks2 {
private boolean mExported;
private boolean mNoPerms;
+ private final ThreadLocal<String> mCallingPackage = new ThreadLocal<String>();
+
private Transport mTransport = new Transport();
/**
@@ -196,8 +195,14 @@ public abstract class ContentProvider implements ComponentCallbacks2 {
return rejectQuery(uri, projection, selection, selectionArgs, sortOrder,
CancellationSignal.fromTransport(cancellationSignal));
}
- return ContentProvider.this.query(uri, projection, selection, selectionArgs, sortOrder,
- CancellationSignal.fromTransport(cancellationSignal));
+ final String original = setCallingPackage(callingPkg);
+ try {
+ return ContentProvider.this.query(
+ uri, projection, selection, selectionArgs, sortOrder,
+ CancellationSignal.fromTransport(cancellationSignal));
+ } finally {
+ setCallingPackage(original);
+ }
}
@Override
@@ -210,7 +215,12 @@ public abstract class ContentProvider implements ComponentCallbacks2 {
if (enforceWritePermission(callingPkg, uri) != AppOpsManager.MODE_ALLOWED) {
return rejectInsert(uri, initialValues);
}
- return ContentProvider.this.insert(uri, initialValues);
+ final String original = setCallingPackage(callingPkg);
+ try {
+ return ContentProvider.this.insert(uri, initialValues);
+ } finally {
+ setCallingPackage(original);
+ }
}
@Override
@@ -218,7 +228,12 @@ public abstract class ContentProvider implements ComponentCallbacks2 {
if (enforceWritePermission(callingPkg, uri) != AppOpsManager.MODE_ALLOWED) {
return 0;
}
- return ContentProvider.this.bulkInsert(uri, initialValues);
+ final String original = setCallingPackage(callingPkg);
+ try {
+ return ContentProvider.this.bulkInsert(uri, initialValues);
+ } finally {
+ setCallingPackage(original);
+ }
}
@Override
@@ -240,7 +255,12 @@ public abstract class ContentProvider implements ComponentCallbacks2 {
}
}
}
- return ContentProvider.this.applyBatch(operations);
+ final String original = setCallingPackage(callingPkg);
+ try {
+ return ContentProvider.this.applyBatch(operations);
+ } finally {
+ setCallingPackage(original);
+ }
}
@Override
@@ -248,7 +268,12 @@ public abstract class ContentProvider implements ComponentCallbacks2 {
if (enforceWritePermission(callingPkg, uri) != AppOpsManager.MODE_ALLOWED) {
return 0;
}
- return ContentProvider.this.delete(uri, selection, selectionArgs);
+ final String original = setCallingPackage(callingPkg);
+ try {
+ return ContentProvider.this.delete(uri, selection, selectionArgs);
+ } finally {
+ setCallingPackage(original);
+ }
}
@Override
@@ -257,26 +282,50 @@ public abstract class ContentProvider implements ComponentCallbacks2 {
if (enforceWritePermission(callingPkg, uri) != AppOpsManager.MODE_ALLOWED) {
return 0;
}
- return ContentProvider.this.update(uri, values, selection, selectionArgs);
+ final String original = setCallingPackage(callingPkg);
+ try {
+ return ContentProvider.this.update(uri, values, selection, selectionArgs);
+ } finally {
+ setCallingPackage(original);
+ }
}
@Override
- public ParcelFileDescriptor openFile(String callingPkg, Uri uri, String mode)
+ public ParcelFileDescriptor openFile(
+ String callingPkg, Uri uri, String mode, ICancellationSignal cancellationSignal)
throws FileNotFoundException {
enforceFilePermission(callingPkg, uri, mode);
- return ContentProvider.this.openFile(uri, mode);
+ final String original = setCallingPackage(callingPkg);
+ try {
+ return ContentProvider.this.openFile(
+ uri, mode, CancellationSignal.fromTransport(cancellationSignal));
+ } finally {
+ setCallingPackage(original);
+ }
}
@Override
- public AssetFileDescriptor openAssetFile(String callingPkg, Uri uri, String mode)
+ public AssetFileDescriptor openAssetFile(
+ String callingPkg, Uri uri, String mode, ICancellationSignal cancellationSignal)
throws FileNotFoundException {
enforceFilePermission(callingPkg, uri, mode);
- return ContentProvider.this.openAssetFile(uri, mode);
+ final String original = setCallingPackage(callingPkg);
+ try {
+ return ContentProvider.this.openAssetFile(
+ uri, mode, CancellationSignal.fromTransport(cancellationSignal));
+ } finally {
+ setCallingPackage(original);
+ }
}
@Override
public Bundle call(String callingPkg, String method, String arg, Bundle extras) {
- return ContentProvider.this.callFromPackage(callingPkg, method, arg, extras);
+ final String original = setCallingPackage(callingPkg);
+ try {
+ return ContentProvider.this.call(method, arg, extras);
+ } finally {
+ setCallingPackage(original);
+ }
}
@Override
@@ -286,16 +335,48 @@ public abstract class ContentProvider implements ComponentCallbacks2 {
@Override
public AssetFileDescriptor openTypedAssetFile(String callingPkg, Uri uri, String mimeType,
- Bundle opts) throws FileNotFoundException {
+ Bundle opts, ICancellationSignal cancellationSignal) throws FileNotFoundException {
enforceFilePermission(callingPkg, uri, "r");
- return ContentProvider.this.openTypedAssetFile(uri, mimeType, opts);
+ final String original = setCallingPackage(callingPkg);
+ try {
+ return ContentProvider.this.openTypedAssetFile(
+ uri, mimeType, opts, CancellationSignal.fromTransport(cancellationSignal));
+ } finally {
+ setCallingPackage(original);
+ }
}
@Override
- public ICancellationSignal createCancellationSignal() throws RemoteException {
+ public ICancellationSignal createCancellationSignal() {
return CancellationSignal.createTransport();
}
+ @Override
+ public Uri canonicalize(String callingPkg, Uri uri) {
+ if (enforceReadPermission(callingPkg, uri) != AppOpsManager.MODE_ALLOWED) {
+ return null;
+ }
+ final String original = setCallingPackage(callingPkg);
+ try {
+ return ContentProvider.this.canonicalize(uri);
+ } finally {
+ setCallingPackage(original);
+ }
+ }
+
+ @Override
+ public Uri uncanonicalize(String callingPkg, Uri uri) {
+ if (enforceReadPermission(callingPkg, uri) != AppOpsManager.MODE_ALLOWED) {
+ return null;
+ }
+ final String original = setCallingPackage(callingPkg);
+ try {
+ return ContentProvider.this.uncanonicalize(uri);
+ } finally {
+ setCallingPackage(original);
+ }
+ }
+
private void enforceFilePermission(String callingPkg, Uri uri, String mode)
throws FileNotFoundException, SecurityException {
if (mode != null && mode.indexOf('w') != -1) {
@@ -458,6 +539,38 @@ public abstract class ContentProvider implements ComponentCallbacks2 {
}
/**
+ * Set the calling package, returning the current value (or {@code null})
+ * which can be used later to restore the previous state.
+ */
+ private String setCallingPackage(String callingPackage) {
+ final String original = mCallingPackage.get();
+ mCallingPackage.set(callingPackage);
+ return original;
+ }
+
+ /**
+ * Return the package name of the caller that initiated the request being
+ * processed on the current thread. The returned package will have been
+ * verified to belong to the calling UID. Returns {@code null} if not
+ * currently processing a request.
+ * <p>
+ * This will always return {@code null} when processing
+ * {@link #getType(Uri)} or {@link #getStreamTypes(Uri, String)} requests.
+ *
+ * @see Binder#getCallingUid()
+ * @see Context#grantUriPermission(String, Uri, int)
+ * @throws SecurityException if the calling package doesn't belong to the
+ * calling UID.
+ */
+ public final String getCallingPackage() {
+ final String pkg = mCallingPackage.get();
+ if (pkg != null) {
+ mTransport.mAppOpsManager.checkPackage(Binder.getCallingUid(), pkg);
+ }
+ return pkg;
+ }
+
+ /**
* Change the permission required to read data from the content
* provider. This is normally set for you from its manifest information
* when the provider is first created.
@@ -526,8 +639,6 @@ public abstract class ContentProvider implements ComponentCallbacks2 {
/** @hide */
public final void setAppOps(int readOp, int writeOp) {
if (!mNoPerms) {
- mTransport.mAppOpsManager = (AppOpsManager)mContext.getSystemService(
- Context.APP_OPS_SERVICE);
mTransport.mReadOp = readOp;
mTransport.mWriteOp = writeOp;
}
@@ -765,6 +876,58 @@ public abstract class ContentProvider implements ComponentCallbacks2 {
public abstract String getType(Uri uri);
/**
+ * Implement this to support canonicalization of URIs that refer to your
+ * content provider. A canonical URI is one that can be transported across
+ * devices, backup/restore, and other contexts, and still be able to refer
+ * to the same data item. Typically this is implemented by adding query
+ * params to the URI allowing the content provider to verify that an incoming
+ * canonical URI references the same data as it was originally intended for and,
+ * if it doesn't, to find that data (if it exists) in the current environment.
+ *
+ * <p>For example, if the content provider holds people and a normal URI in it
+ * is created with a row index into that people database, the cananical representation
+ * may have an additional query param at the end which specifies the name of the
+ * person it is intended for. Later calls into the provider with that URI will look
+ * up the row of that URI's base index and, if it doesn't match or its entry's
+ * name doesn't match the name in the query param, perform a query on its database
+ * to find the correct row to operate on.</p>
+ *
+ * <p>If you implement support for canonical URIs, <b>all</b> incoming calls with
+ * URIs (including this one) must perform this verification and recovery of any
+ * canonical URIs they receive. In addition, you must also implement
+ * {@link #uncanonicalize} to strip the canonicalization of any of these URIs.</p>
+ *
+ * <p>The default implementation of this method returns null, indicating that
+ * canonical URIs are not supported.</p>
+ *
+ * @param url The Uri to canonicalize.
+ *
+ * @return Return the canonical representation of <var>url</var>, or null if
+ * canonicalization of that Uri is not supported.
+ */
+ public Uri canonicalize(Uri url) {
+ return null;
+ }
+
+ /**
+ * Remove canonicalization from canonical URIs previously returned by
+ * {@link #canonicalize}. For example, if your implementation is to add
+ * a query param to canonicalize a URI, this method can simply trip any
+ * query params on the URI. The default implementation always returns the
+ * same <var>url</var> that was passed in.
+ *
+ * @param url The Uri to remove any canonicalization from.
+ *
+ * @return Return the non-canonical representation of <var>url</var>, return
+ * the <var>url</var> as-is if there is nothing to do, or return null if
+ * the data identified by the canonical representation can not be found in
+ * the current environment.
+ */
+ public Uri uncanonicalize(Uri url) {
+ return url;
+ }
+
+ /**
* @hide
* Implementation when a caller has performed an insert on the content
* provider, but that call has been rejected for the operation given
@@ -874,6 +1037,18 @@ public abstract class ContentProvider implements ComponentCallbacks2 {
* <p>The returned ParcelFileDescriptor is owned by the caller, so it is
* their responsibility to close it when done. That is, the implementation
* of this method should create a new ParcelFileDescriptor for each call.
+ * <p>
+ * If opened with the exclusive "r" or "w" modes, the returned
+ * ParcelFileDescriptor can be a pipe or socket pair to enable streaming
+ * of data. Opening with the "rw" or "rwt" modes implies a file on disk that
+ * supports seeking.
+ * <p>
+ * If you need to detect when the returned ParcelFileDescriptor has been
+ * closed, or if the remote process has crashed or encountered some other
+ * error, you can use {@link ParcelFileDescriptor#open(File, int,
+ * android.os.Handler, android.os.ParcelFileDescriptor.OnCloseListener)},
+ * {@link ParcelFileDescriptor#createReliablePipe()}, or
+ * {@link ParcelFileDescriptor#createReliableSocketPair()}.
*
* <p class="note">For use in Intents, you will want to implement {@link #getType}
* to return the appropriate MIME type for the data returned here with
@@ -903,6 +1078,7 @@ public abstract class ContentProvider implements ComponentCallbacks2 {
* @see #openAssetFile(Uri, String)
* @see #openFileHelper(Uri, String)
* @see #getType(android.net.Uri)
+ * @see ParcelFileDescriptor#parseMode(String)
*/
public ParcelFileDescriptor openFile(Uri uri, String mode)
throws FileNotFoundException {
@@ -911,6 +1087,75 @@ public abstract class ContentProvider implements ComponentCallbacks2 {
}
/**
+ * Override this to handle requests to open a file blob.
+ * The default implementation always throws {@link FileNotFoundException}.
+ * This method can be called from multiple threads, as described in
+ * <a href="{@docRoot}guide/topics/fundamentals/processes-and-threads.html#Threads">Processes
+ * and Threads</a>.
+ *
+ * <p>This method returns a ParcelFileDescriptor, which is returned directly
+ * to the caller. This way large data (such as images and documents) can be
+ * returned without copying the content.
+ *
+ * <p>The returned ParcelFileDescriptor is owned by the caller, so it is
+ * their responsibility to close it when done. That is, the implementation
+ * of this method should create a new ParcelFileDescriptor for each call.
+ * <p>
+ * If opened with the exclusive "r" or "w" modes, the returned
+ * ParcelFileDescriptor can be a pipe or socket pair to enable streaming
+ * of data. Opening with the "rw" or "rwt" modes implies a file on disk that
+ * supports seeking.
+ * <p>
+ * If you need to detect when the returned ParcelFileDescriptor has been
+ * closed, or if the remote process has crashed or encountered some other
+ * error, you can use {@link ParcelFileDescriptor#open(File, int,
+ * android.os.Handler, android.os.ParcelFileDescriptor.OnCloseListener)},
+ * {@link ParcelFileDescriptor#createReliablePipe()}, or
+ * {@link ParcelFileDescriptor#createReliableSocketPair()}.
+ *
+ * <p class="note">For use in Intents, you will want to implement {@link #getType}
+ * to return the appropriate MIME type for the data returned here with
+ * the same URI. This will allow intent resolution to automatically determine the data MIME
+ * type and select the appropriate matching targets as part of its operation.</p>
+ *
+ * <p class="note">For better interoperability with other applications, it is recommended
+ * that for any URIs that can be opened, you also support queries on them
+ * containing at least the columns specified by {@link android.provider.OpenableColumns}.
+ * You may also want to support other common columns if you have additional meta-data
+ * to supply, such as {@link android.provider.MediaStore.MediaColumns#DATE_ADDED}
+ * in {@link android.provider.MediaStore.MediaColumns}.</p>
+ *
+ * @param uri The URI whose file is to be opened.
+ * @param mode Access mode for the file. May be "r" for read-only access,
+ * "w" for write-only access, "rw" for read and write access, or
+ * "rwt" for read and write access that truncates any existing
+ * file.
+ * @param signal A signal to cancel the operation in progress, or
+ * {@code null} if none. For example, if you are downloading a
+ * file from the network to service a "rw" mode request, you
+ * should periodically call
+ * {@link CancellationSignal#throwIfCanceled()} to check whether
+ * the client has canceled the request and abort the download.
+ *
+ * @return Returns a new ParcelFileDescriptor which you can use to access
+ * the file.
+ *
+ * @throws FileNotFoundException Throws FileNotFoundException if there is
+ * no file associated with the given URI or the mode is invalid.
+ * @throws SecurityException Throws SecurityException if the caller does
+ * not have permission to access the file.
+ *
+ * @see #openAssetFile(Uri, String)
+ * @see #openFileHelper(Uri, String)
+ * @see #getType(android.net.Uri)
+ * @see ParcelFileDescriptor#parseMode(String)
+ */
+ public ParcelFileDescriptor openFile(Uri uri, String mode, CancellationSignal signal)
+ throws FileNotFoundException {
+ return openFile(uri, mode);
+ }
+
+ /**
* This is like {@link #openFile}, but can be implemented by providers
* that need to be able to return sub-sections of files, often assets
* inside of their .apk.
@@ -924,11 +1169,14 @@ public abstract class ContentProvider implements ComponentCallbacks2 {
* {@link ContentResolver#openInputStream ContentResolver.openInputStream}
* or {@link ContentResolver#openOutputStream ContentResolver.openOutputStream}
* methods.
+ * <p>
+ * The returned AssetFileDescriptor can be a pipe or socket pair to enable
+ * streaming of data.
*
* <p class="note">If you are implementing this to return a full file, you
* should create the AssetFileDescriptor with
* {@link AssetFileDescriptor#UNKNOWN_LENGTH} to be compatible with
- * applications that can not handle sub-sections of files.</p>
+ * applications that cannot handle sub-sections of files.</p>
*
* <p class="note">For use in Intents, you will want to implement {@link #getType}
* to return the appropriate MIME type for the data returned here with
@@ -965,6 +1213,68 @@ public abstract class ContentProvider implements ComponentCallbacks2 {
}
/**
+ * This is like {@link #openFile}, but can be implemented by providers
+ * that need to be able to return sub-sections of files, often assets
+ * inside of their .apk.
+ * This method can be called from multiple threads, as described in
+ * <a href="{@docRoot}guide/topics/fundamentals/processes-and-threads.html#Threads">Processes
+ * and Threads</a>.
+ *
+ * <p>If you implement this, your clients must be able to deal with such
+ * file slices, either directly with
+ * {@link ContentResolver#openAssetFileDescriptor}, or by using the higher-level
+ * {@link ContentResolver#openInputStream ContentResolver.openInputStream}
+ * or {@link ContentResolver#openOutputStream ContentResolver.openOutputStream}
+ * methods.
+ * <p>
+ * The returned AssetFileDescriptor can be a pipe or socket pair to enable
+ * streaming of data.
+ *
+ * <p class="note">If you are implementing this to return a full file, you
+ * should create the AssetFileDescriptor with
+ * {@link AssetFileDescriptor#UNKNOWN_LENGTH} to be compatible with
+ * applications that cannot handle sub-sections of files.</p>
+ *
+ * <p class="note">For use in Intents, you will want to implement {@link #getType}
+ * to return the appropriate MIME type for the data returned here with
+ * the same URI. This will allow intent resolution to automatically determine the data MIME
+ * type and select the appropriate matching targets as part of its operation.</p>
+ *
+ * <p class="note">For better interoperability with other applications, it is recommended
+ * that for any URIs that can be opened, you also support queries on them
+ * containing at least the columns specified by {@link android.provider.OpenableColumns}.</p>
+ *
+ * @param uri The URI whose file is to be opened.
+ * @param mode Access mode for the file. May be "r" for read-only access,
+ * "w" for write-only access (erasing whatever data is currently in
+ * the file), "wa" for write-only access to append to any existing data,
+ * "rw" for read and write access on any existing data, and "rwt" for read
+ * and write access that truncates any existing file.
+ * @param signal A signal to cancel the operation in progress, or
+ * {@code null} if none. For example, if you are downloading a
+ * file from the network to service a "rw" mode request, you
+ * should periodically call
+ * {@link CancellationSignal#throwIfCanceled()} to check whether
+ * the client has canceled the request and abort the download.
+ *
+ * @return Returns a new AssetFileDescriptor which you can use to access
+ * the file.
+ *
+ * @throws FileNotFoundException Throws FileNotFoundException if there is
+ * no file associated with the given URI or the mode is invalid.
+ * @throws SecurityException Throws SecurityException if the caller does
+ * not have permission to access the file.
+ *
+ * @see #openFile(Uri, String)
+ * @see #openFileHelper(Uri, String)
+ * @see #getType(android.net.Uri)
+ */
+ public AssetFileDescriptor openAssetFile(Uri uri, String mode, CancellationSignal signal)
+ throws FileNotFoundException {
+ return openAssetFile(uri, mode);
+ }
+
+ /**
* Convenience for subclasses that wish to implement {@link #openFile}
* by looking up a column named "_data" at the given URI.
*
@@ -1002,7 +1312,7 @@ public abstract class ContentProvider implements ComponentCallbacks2 {
throw new FileNotFoundException("Column _data not found.");
}
- int modeBits = ContentResolver.modeToMode(uri, mode);
+ int modeBits = ParcelFileDescriptor.parseMode(mode);
return ParcelFileDescriptor.open(new File(path), modeBits);
}
@@ -1041,6 +1351,9 @@ public abstract class ContentProvider implements ComponentCallbacks2 {
*
* <p>See {@link ClipData} for examples of the use and implementation
* of this method.
+ * <p>
+ * The returned AssetFileDescriptor can be a pipe or socket pair to enable
+ * streaming of data.
*
* <p class="note">For better interoperability with other applications, it is recommended
* that for any URIs that can be opened, you also support queries on them
@@ -1086,6 +1399,64 @@ public abstract class ContentProvider implements ComponentCallbacks2 {
throw new FileNotFoundException("Can't open " + uri + " as type " + mimeTypeFilter);
}
+
+ /**
+ * Called by a client to open a read-only stream containing data of a
+ * particular MIME type. This is like {@link #openAssetFile(Uri, String)},
+ * except the file can only be read-only and the content provider may
+ * perform data conversions to generate data of the desired type.
+ *
+ * <p>The default implementation compares the given mimeType against the
+ * result of {@link #getType(Uri)} and, if they match, simply calls
+ * {@link #openAssetFile(Uri, String)}.
+ *
+ * <p>See {@link ClipData} for examples of the use and implementation
+ * of this method.
+ * <p>
+ * The returned AssetFileDescriptor can be a pipe or socket pair to enable
+ * streaming of data.
+ *
+ * <p class="note">For better interoperability with other applications, it is recommended
+ * that for any URIs that can be opened, you also support queries on them
+ * containing at least the columns specified by {@link android.provider.OpenableColumns}.
+ * You may also want to support other common columns if you have additional meta-data
+ * to supply, such as {@link android.provider.MediaStore.MediaColumns#DATE_ADDED}
+ * in {@link android.provider.MediaStore.MediaColumns}.</p>
+ *
+ * @param uri The data in the content provider being queried.
+ * @param mimeTypeFilter The type of data the client desires. May be
+ * a pattern, such as *\/*, if the caller does not have specific type
+ * requirements; in this case the content provider will pick its best
+ * type matching the pattern.
+ * @param opts Additional options from the client. The definitions of
+ * these are specific to the content provider being called.
+ * @param signal A signal to cancel the operation in progress, or
+ * {@code null} if none. For example, if you are downloading a
+ * file from the network to service a "rw" mode request, you
+ * should periodically call
+ * {@link CancellationSignal#throwIfCanceled()} to check whether
+ * the client has canceled the request and abort the download.
+ *
+ * @return Returns a new AssetFileDescriptor from which the client can
+ * read data of the desired type.
+ *
+ * @throws FileNotFoundException Throws FileNotFoundException if there is
+ * no file associated with the given URI or the mode is invalid.
+ * @throws SecurityException Throws SecurityException if the caller does
+ * not have permission to access the data.
+ * @throws IllegalArgumentException Throws IllegalArgumentException if the
+ * content provider does not support the requested MIME type.
+ *
+ * @see #getStreamTypes(Uri, String)
+ * @see #openAssetFile(Uri, String)
+ * @see ClipDescription#compareMimeTypes(String, String)
+ */
+ public AssetFileDescriptor openTypedAssetFile(
+ Uri uri, String mimeTypeFilter, Bundle opts, CancellationSignal signal)
+ throws FileNotFoundException {
+ return openTypedAssetFile(uri, mimeTypeFilter, opts);
+ }
+
/**
* Interface to write a stream of data to a pipe. Use with
* {@link ContentProvider#openPipeHelper}.
@@ -1204,6 +1575,10 @@ public abstract class ContentProvider implements ComponentCallbacks2 {
*/
if (mContext == null) {
mContext = context;
+ if (context != null) {
+ mTransport.mAppOpsManager = (AppOpsManager) context.getSystemService(
+ Context.APP_OPS_SERVICE);
+ }
mMyUid = Process.myUid();
if (info != null) {
setReadPermission(info.readPermission);
@@ -1243,15 +1618,6 @@ public abstract class ContentProvider implements ComponentCallbacks2 {
}
/**
- * @hide
- * Front-end to {@link #call(String, String, android.os.Bundle)} that provides the name
- * of the calling package.
- */
- public Bundle callFromPackage(String callingPackag, String method, String arg, Bundle extras) {
- return call(method, arg, extras);
- }
-
- /**
* Call a provider-defined method. This can be used to implement
* interfaces that are cheaper and/or unnatural for a table-like
* model.