diff options
Diffstat (limited to 'core/java/android')
| -rw-r--r-- | core/java/android/content/ContentProvider.java | 78 | ||||
| -rw-r--r-- | core/java/android/content/ContentProviderClient.java | 24 | ||||
| -rw-r--r-- | core/java/android/content/ContentProviderNative.java | 65 | ||||
| -rw-r--r-- | core/java/android/content/ContentResolver.java | 80 | ||||
| -rw-r--r-- | core/java/android/content/IContentProvider.java | 5 | ||||
| -rw-r--r-- | core/java/android/print/IPrinterDiscoveryObserver.aidl | 1 |
6 files changed, 251 insertions, 2 deletions
diff --git a/core/java/android/content/ContentProvider.java b/core/java/android/content/ContentProvider.java index 24c396a..65a3a07 100644 --- a/core/java/android/content/ContentProvider.java +++ b/core/java/android/content/ContentProvider.java @@ -348,10 +348,36 @@ public abstract class ContentProvider implements ComponentCallbacks2 { } @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; + } + mCallingPackage.set(callingPkg); + try { + return ContentProvider.this.canonicalize(uri); + } finally { + mCallingPackage.set(null); + } + } + + @Override + public Uri uncanonicalize(String callingPkg, Uri uri) { + if (enforceReadPermission(callingPkg, uri) != AppOpsManager.MODE_ALLOWED) { + return null; + } + mCallingPackage.set(callingPkg); + try { + return ContentProvider.this.uncanonicalize(uri); + } finally { + mCallingPackage.set(null); + } + } + private void enforceFilePermission(String callingPkg, Uri uri, String mode) throws FileNotFoundException, SecurityException { if (mode != null && mode.indexOf('w') != -1) { @@ -841,6 +867,56 @@ 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>, or return + * the <var>url</var> as-is if there is nothing to do. Never return null. + */ + 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 diff --git a/core/java/android/content/ContentProviderClient.java b/core/java/android/content/ContentProviderClient.java index 4e8dd82..e6d9b24 100644 --- a/core/java/android/content/ContentProviderClient.java +++ b/core/java/android/content/ContentProviderClient.java @@ -110,6 +110,30 @@ public class ContentProviderClient { } } + /** See {@link ContentProvider#canonicalize} */ + public final Uri canonicalize(Uri url) throws RemoteException { + try { + return mContentProvider.canonicalize(mPackageName, url); + } catch (DeadObjectException e) { + if (!mStable) { + mContentResolver.unstableProviderDied(mContentProvider); + } + throw e; + } + } + + /** See {@link ContentProvider#uncanonicalize} */ + public final Uri uncanonicalize(Uri url) throws RemoteException { + try { + return mContentProvider.uncanonicalize(mPackageName, url); + } catch (DeadObjectException e) { + if (!mStable) { + mContentResolver.unstableProviderDied(mContentProvider); + } + throw e; + } + } + /** See {@link ContentProvider#insert ContentProvider.insert} */ public Uri insert(Uri url, ContentValues initialValues) throws RemoteException { diff --git a/core/java/android/content/ContentProviderNative.java b/core/java/android/content/ContentProviderNative.java index 744e68c..bcf0b63 100644 --- a/core/java/android/content/ContentProviderNative.java +++ b/core/java/android/content/ContentProviderNative.java @@ -323,6 +323,30 @@ abstract public class ContentProviderNative extends Binder implements IContentPr reply.writeStrongBinder(cancellationSignal.asBinder()); return true; } + + case CANONICALIZE_TRANSACTION: + { + data.enforceInterface(IContentProvider.descriptor); + String callingPkg = data.readString(); + Uri url = Uri.CREATOR.createFromParcel(data); + + Uri out = canonicalize(callingPkg, url); + reply.writeNoException(); + Uri.writeToParcel(reply, out); + return true; + } + + case UNCANONICALIZE_TRANSACTION: + { + data.enforceInterface(IContentProvider.descriptor); + String callingPkg = data.readString(); + Uri url = Uri.CREATOR.createFromParcel(data); + + Uri out = uncanonicalize(callingPkg, url); + reply.writeNoException(); + Uri.writeToParcel(reply, out); + return true; + } } } catch (Exception e) { DatabaseUtils.writeExceptionToParcel(reply, e); @@ -685,5 +709,46 @@ final class ContentProviderProxy implements IContentProvider } } + public Uri canonicalize(String callingPkg, Uri url) throws RemoteException + { + Parcel data = Parcel.obtain(); + Parcel reply = Parcel.obtain(); + try { + data.writeInterfaceToken(IContentProvider.descriptor); + + data.writeString(callingPkg); + url.writeToParcel(data, 0); + + mRemote.transact(IContentProvider.CANONICALIZE_TRANSACTION, data, reply, 0); + + DatabaseUtils.readExceptionFromParcel(reply); + Uri out = Uri.CREATOR.createFromParcel(reply); + return out; + } finally { + data.recycle(); + reply.recycle(); + } + } + + public Uri uncanonicalize(String callingPkg, Uri url) throws RemoteException { + Parcel data = Parcel.obtain(); + Parcel reply = Parcel.obtain(); + try { + data.writeInterfaceToken(IContentProvider.descriptor); + + data.writeString(callingPkg); + url.writeToParcel(data, 0); + + mRemote.transact(IContentProvider.UNCANONICALIZE_TRANSACTION, data, reply, 0); + + DatabaseUtils.readExceptionFromParcel(reply); + Uri out = Uri.CREATOR.createFromParcel(reply); + return out; + } finally { + data.recycle(); + reply.recycle(); + } + } + private IBinder mRemote; } diff --git a/core/java/android/content/ContentResolver.java b/core/java/android/content/ContentResolver.java index 8a5a56c..9f462aa 100644 --- a/core/java/android/content/ContentResolver.java +++ b/core/java/android/content/ContentResolver.java @@ -497,6 +497,86 @@ public abstract class ContentResolver { } /** + * Transform the given <var>url</var> to a canonical representation of + * its referenced resource, which can be used across devices, persisted, + * backed up and restored, etc. The returned Uri is still a fully capable + * Uri for use with its content provider, allowing you to do all of the + * same content provider operations as with the original Uri -- + * {@link #query}, {@link #openInputStream(android.net.Uri)}, etc. The + * only difference in behavior between the original and new Uris is that + * the content provider may need to do some additional work at each call + * using it to resolve it to the correct resource, especially if the + * canonical Uri has been moved to a different environment. + * + * <p>If you are moving a canonical Uri between environments, you should + * perform another call to {@link #canonicalize} with that original Uri to + * re-canonicalize it for the current environment. Alternatively, you may + * want to use {@link #uncanonicalize} to transform it to a non-canonical + * Uri that works only in the current environment but potentially more + * efficiently than the canonical representation.</p> + * + * @param url The {@link Uri} that is to be transformed to a canonical + * representation. Like all resolver calls, the input can be either + * a non-canonical or canonical Uri. + * + * @return Returns the official canonical representation of <var>url</var>, + * or null if the content provider does not support a canonical representation + * of the given Uri. Many providers may not support canonicalization of some + * or all of their Uris. + * + * @see #uncanonicalize + */ + public final Uri canonicalize(Uri url) { + IContentProvider provider = acquireProvider(url); + if (provider == null) { + return null; + } + + try { + return provider.canonicalize(mPackageName, url); + } catch (RemoteException e) { + // Arbitrary and not worth documenting, as Activity + // Manager will kill this process shortly anyway. + return null; + } finally { + releaseProvider(provider); + } + } + + /** + * Given a canonical Uri previously generated by {@link #canonicalize}, convert + * it to its local non-canonical form. This can be useful in some cases where + * you know that you will only be using the Uri in the current environment and + * want to avoid any possible overhead when using it with the content + * provider. + * + * @param url The canonical {@link Uri} that is to be convered back to its + * non-canonical form. + * + * @return Returns the non-canonical representation of <var>url</var>. This + * function never returns null; if there is no conversion to be done, it returns + * the same Uri that was provided. + * + * @see #canonicalize + */ + public final Uri uncanonicalize(Uri url) { + IContentProvider provider = acquireProvider(url); + if (provider == null) { + return null; + } + + try { + return provider.uncanonicalize(mPackageName, url); + } catch (RemoteException e) { + // Arbitrary and not worth documenting, as Activity + // Manager will kill this process shortly anyway. + return null; + } finally { + releaseProvider(provider); + } + } + + /** * Open a stream on to the content associated with a content URI. If there * is no data associated with the URI, FileNotFoundException is thrown. * diff --git a/core/java/android/content/IContentProvider.java b/core/java/android/content/IContentProvider.java index 6ea8876..f92a404 100644 --- a/core/java/android/content/IContentProvider.java +++ b/core/java/android/content/IContentProvider.java @@ -59,6 +59,9 @@ public interface IContentProvider extends IInterface { throws RemoteException; public ICancellationSignal createCancellationSignal() throws RemoteException; + public Uri canonicalize(String callingPkg, Uri uri) throws RemoteException; + public Uri uncanonicalize(String callingPkg, Uri uri) throws RemoteException; + // Data interchange. public String[] getStreamTypes(Uri url, String mimeTypeFilter) throws RemoteException; public AssetFileDescriptor openTypedAssetFile(String callingPkg, Uri url, String mimeType, @@ -80,4 +83,6 @@ public interface IContentProvider extends IInterface { static final int GET_STREAM_TYPES_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION + 21; static final int OPEN_TYPED_ASSET_FILE_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION + 22; static final int CREATE_CANCELATION_SIGNAL_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION + 23; + static final int CANONICALIZE_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION + 24; + static final int UNCANONICALIZE_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION + 25; } diff --git a/core/java/android/print/IPrinterDiscoveryObserver.aidl b/core/java/android/print/IPrinterDiscoveryObserver.aidl index 71198f7..b558011 100644 --- a/core/java/android/print/IPrinterDiscoveryObserver.aidl +++ b/core/java/android/print/IPrinterDiscoveryObserver.aidl @@ -16,7 +16,6 @@ package android.print; -import android.print.IPrintClient; import android.print.PrinterId; import android.print.PrinterInfo; |
