/* * Copyright (C) 2006 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.content; import android.annotation.NonNull; import android.annotation.Nullable; import android.compat.annotation.UnsupportedAppUsage; import android.content.res.AssetFileDescriptor; import android.database.BulkCursorDescriptor; import android.database.BulkCursorToCursorAdaptor; import android.database.Cursor; import android.database.CursorToBulkCursorAdaptor; import android.database.DatabaseUtils; import android.database.IContentObserver; import android.net.Uri; import android.os.Binder; import android.os.Bundle; import android.os.IBinder; import android.os.ICancellationSignal; import android.os.Parcel; import android.os.ParcelFileDescriptor; import android.os.Parcelable; import android.os.RemoteCallback; import android.os.RemoteException; import java.io.FileNotFoundException; import java.util.ArrayList; /** * {@hide} */ abstract public class ContentProviderNative extends Binder implements IContentProvider { public ContentProviderNative() { attachInterface(this, descriptor); } /** * Cast a Binder object into a content resolver interface, generating * a proxy if needed. */ @UnsupportedAppUsage static public IContentProvider asInterface(IBinder obj) { if (obj == null) { return null; } IContentProvider in = (IContentProvider)obj.queryLocalInterface(descriptor); if (in != null) { return in; } return new ContentProviderProxy(obj); } /** * Gets the name of the content provider. * Should probably be part of the {@link IContentProvider} interface. * @return The content provider name. */ public abstract String getProviderName(); @Override public boolean onTransact(int code, Parcel data, Parcel reply, int flags) throws RemoteException { try { switch (code) { case QUERY_TRANSACTION: { data.enforceInterface(IContentProvider.descriptor); AttributionSource attributionSource = AttributionSource.CREATOR .createFromParcel(data); Uri url = Uri.CREATOR.createFromParcel(data); // String[] projection int num = data.readInt(); String[] projection = null; if (num > 0) { projection = new String[num]; for (int i = 0; i < num; i++) { projection[i] = data.readString(); } } Bundle queryArgs = data.readBundle(); IContentObserver observer = IContentObserver.Stub.asInterface( data.readStrongBinder()); ICancellationSignal cancellationSignal = ICancellationSignal.Stub.asInterface( data.readStrongBinder()); Cursor cursor = query(attributionSource, url, projection, queryArgs, cancellationSignal); if (cursor != null) { CursorToBulkCursorAdaptor adaptor = null; try { adaptor = new CursorToBulkCursorAdaptor(cursor, observer, getProviderName()); cursor = null; BulkCursorDescriptor d = adaptor.getBulkCursorDescriptor(); adaptor = null; reply.writeNoException(); reply.writeInt(1); d.writeToParcel(reply, Parcelable.PARCELABLE_WRITE_RETURN_VALUE); } finally { // Close cursor if an exception was thrown while constructing the adaptor. if (adaptor != null) { adaptor.close(); } if (cursor != null) { cursor.close(); } } } else { reply.writeNoException(); reply.writeInt(0); } return true; } case GET_TYPE_TRANSACTION: { data.enforceInterface(IContentProvider.descriptor); AttributionSource attributionSource = AttributionSource.CREATOR .createFromParcel(data); Uri url = Uri.CREATOR.createFromParcel(data); String type = getType(attributionSource, url); reply.writeNoException(); reply.writeString(type); return true; } case GET_TYPE_ASYNC_TRANSACTION: { data.enforceInterface(IContentProvider.descriptor); AttributionSource attributionSource = AttributionSource.CREATOR .createFromParcel(data); Uri url = Uri.CREATOR.createFromParcel(data); RemoteCallback callback = RemoteCallback.CREATOR.createFromParcel(data); getTypeAsync(attributionSource, url, callback); return true; } case GET_TYPE_ANONYMOUS_ASYNC_TRANSACTION: { data.enforceInterface(IContentProvider.descriptor); Uri url = Uri.CREATOR.createFromParcel(data); RemoteCallback callback = RemoteCallback.CREATOR.createFromParcel(data); getTypeAnonymousAsync(url, callback); return true; } case INSERT_TRANSACTION: { data.enforceInterface(IContentProvider.descriptor); AttributionSource attributionSource = AttributionSource.CREATOR .createFromParcel(data); Uri url = Uri.CREATOR.createFromParcel(data); ContentValues values = ContentValues.CREATOR.createFromParcel(data); Bundle extras = data.readBundle(); Uri out = insert(attributionSource, url, values, extras); reply.writeNoException(); Uri.writeToParcel(reply, out); return true; } case BULK_INSERT_TRANSACTION: { data.enforceInterface(IContentProvider.descriptor); AttributionSource attributionSource = AttributionSource.CREATOR .createFromParcel(data); Uri url = Uri.CREATOR.createFromParcel(data); ContentValues[] values = data.createTypedArray(ContentValues.CREATOR); int count = bulkInsert(attributionSource, url, values); reply.writeNoException(); reply.writeInt(count); return true; } case APPLY_BATCH_TRANSACTION: { data.enforceInterface(IContentProvider.descriptor); AttributionSource attributionSource = AttributionSource.CREATOR .createFromParcel(data); String authority = data.readString(); final int numOperations = data.readInt(); final ArrayList operations = new ArrayList<>(numOperations); for (int i = 0; i < numOperations; i++) { operations.add(i, ContentProviderOperation.CREATOR.createFromParcel(data)); } final ContentProviderResult[] results = applyBatch(attributionSource, authority, operations); reply.writeNoException(); reply.writeTypedArray(results, 0); return true; } case DELETE_TRANSACTION: { data.enforceInterface(IContentProvider.descriptor); AttributionSource attributionSource = AttributionSource.CREATOR .createFromParcel(data); Uri url = Uri.CREATOR.createFromParcel(data); Bundle extras = data.readBundle(); int count = delete(attributionSource, url, extras); reply.writeNoException(); reply.writeInt(count); return true; } case UPDATE_TRANSACTION: { data.enforceInterface(IContentProvider.descriptor); AttributionSource attributionSource = AttributionSource.CREATOR .createFromParcel(data); Uri url = Uri.CREATOR.createFromParcel(data); ContentValues values = ContentValues.CREATOR.createFromParcel(data); Bundle extras = data.readBundle(); int count = update(attributionSource, url, values, extras); reply.writeNoException(); reply.writeInt(count); return true; } case OPEN_FILE_TRANSACTION: { data.enforceInterface(IContentProvider.descriptor); AttributionSource attributionSource = AttributionSource.CREATOR .createFromParcel(data); Uri url = Uri.CREATOR.createFromParcel(data); String mode = data.readString(); ICancellationSignal signal = ICancellationSignal.Stub.asInterface( data.readStrongBinder()); ParcelFileDescriptor fd; fd = openFile(attributionSource, url, mode, signal); reply.writeNoException(); if (fd != null) { reply.writeInt(1); fd.writeToParcel(reply, Parcelable.PARCELABLE_WRITE_RETURN_VALUE); } else { reply.writeInt(0); } return true; } case OPEN_ASSET_FILE_TRANSACTION: { data.enforceInterface(IContentProvider.descriptor); AttributionSource attributionSource = AttributionSource.CREATOR .createFromParcel(data); Uri url = Uri.CREATOR.createFromParcel(data); String mode = data.readString(); ICancellationSignal signal = ICancellationSignal.Stub.asInterface( data.readStrongBinder()); AssetFileDescriptor fd; fd = openAssetFile(attributionSource, url, mode, signal); reply.writeNoException(); if (fd != null) { reply.writeInt(1); fd.writeToParcel(reply, Parcelable.PARCELABLE_WRITE_RETURN_VALUE); } else { reply.writeInt(0); } return true; } case CALL_TRANSACTION: { data.enforceInterface(IContentProvider.descriptor); AttributionSource attributionSource = AttributionSource.CREATOR .createFromParcel(data); String authority = data.readString(); String method = data.readString(); String stringArg = data.readString(); Bundle extras = data.readBundle(); Bundle responseBundle = call(attributionSource, authority, method, stringArg, extras); reply.writeNoException(); reply.writeBundle(responseBundle); return true; } case GET_STREAM_TYPES_TRANSACTION: { data.enforceInterface(IContentProvider.descriptor); AttributionSource attributionSource = AttributionSource.CREATOR .createFromParcel(data); Uri url = Uri.CREATOR.createFromParcel(data); String mimeTypeFilter = data.readString(); String[] types = getStreamTypes(attributionSource, url, mimeTypeFilter); reply.writeNoException(); reply.writeStringArray(types); return true; } case OPEN_TYPED_ASSET_FILE_TRANSACTION: { data.enforceInterface(IContentProvider.descriptor); AttributionSource attributionSource = AttributionSource.CREATOR .createFromParcel(data); Uri url = Uri.CREATOR.createFromParcel(data); String mimeType = data.readString(); Bundle opts = data.readBundle(); ICancellationSignal signal = ICancellationSignal.Stub.asInterface( data.readStrongBinder()); AssetFileDescriptor fd; fd = openTypedAssetFile(attributionSource, url, mimeType, opts, signal); reply.writeNoException(); if (fd != null) { reply.writeInt(1); fd.writeToParcel(reply, Parcelable.PARCELABLE_WRITE_RETURN_VALUE); } else { reply.writeInt(0); } return true; } case CREATE_CANCELATION_SIGNAL_TRANSACTION: { data.enforceInterface(IContentProvider.descriptor); ICancellationSignal cancellationSignal = createCancellationSignal(); reply.writeNoException(); reply.writeStrongBinder(cancellationSignal.asBinder()); return true; } case CANONICALIZE_TRANSACTION: { data.enforceInterface(IContentProvider.descriptor); AttributionSource attributionSource = AttributionSource.CREATOR .createFromParcel(data); Uri url = Uri.CREATOR.createFromParcel(data); Uri out = canonicalize(attributionSource, url); reply.writeNoException(); Uri.writeToParcel(reply, out); return true; } case CANONICALIZE_ASYNC_TRANSACTION: { data.enforceInterface(IContentProvider.descriptor); AttributionSource attributionSource = AttributionSource.CREATOR .createFromParcel(data); Uri uri = Uri.CREATOR.createFromParcel(data); RemoteCallback callback = RemoteCallback.CREATOR.createFromParcel(data); canonicalizeAsync(attributionSource, uri, callback); return true; } case UNCANONICALIZE_TRANSACTION: { data.enforceInterface(IContentProvider.descriptor); AttributionSource attributionSource = AttributionSource.CREATOR .createFromParcel(data); Uri url = Uri.CREATOR.createFromParcel(data); Uri out = uncanonicalize(attributionSource, url); reply.writeNoException(); Uri.writeToParcel(reply, out); return true; } case UNCANONICALIZE_ASYNC_TRANSACTION: { data.enforceInterface(IContentProvider.descriptor); AttributionSource attributionSource = AttributionSource.CREATOR .createFromParcel(data); Uri uri = Uri.CREATOR.createFromParcel(data); RemoteCallback callback = RemoteCallback.CREATOR.createFromParcel(data); uncanonicalizeAsync(attributionSource, uri, callback); return true; } case REFRESH_TRANSACTION: { data.enforceInterface(IContentProvider.descriptor); AttributionSource attributionSource = AttributionSource.CREATOR .createFromParcel(data); Uri url = Uri.CREATOR.createFromParcel(data); Bundle extras = data.readBundle(); ICancellationSignal signal = ICancellationSignal.Stub.asInterface( data.readStrongBinder()); boolean out = refresh(attributionSource, url, extras, signal); reply.writeNoException(); reply.writeInt(out ? 0 : -1); return true; } case CHECK_URI_PERMISSION_TRANSACTION: { data.enforceInterface(IContentProvider.descriptor); AttributionSource attributionSource = AttributionSource.CREATOR .createFromParcel(data); Uri uri = Uri.CREATOR.createFromParcel(data); int uid = data.readInt(); int modeFlags = data.readInt(); int out = checkUriPermission(attributionSource, uri, uid, modeFlags); reply.writeNoException(); reply.writeInt(out); return true; } } } catch (Exception e) { DatabaseUtils.writeExceptionToParcel(reply, e); return true; } return super.onTransact(code, data, reply, flags); } @Override public IBinder asBinder() { return this; } } final class ContentProviderProxy implements IContentProvider { public ContentProviderProxy(IBinder remote) { mRemote = remote; } @Override public IBinder asBinder() { return mRemote; } @Override public Cursor query(@NonNull AttributionSource attributionSource, Uri url, @Nullable String[] projection, @Nullable Bundle queryArgs, @Nullable ICancellationSignal cancellationSignal) throws RemoteException { BulkCursorToCursorAdaptor adaptor = new BulkCursorToCursorAdaptor(); Parcel data = Parcel.obtain(); Parcel reply = Parcel.obtain(); try { data.writeInterfaceToken(IContentProvider.descriptor); attributionSource.writeToParcel(data, 0); url.writeToParcel(data, 0); int length = 0; if (projection != null) { length = projection.length; } data.writeInt(length); for (int i = 0; i < length; i++) { data.writeString(projection[i]); } data.writeBundle(queryArgs); data.writeStrongBinder(adaptor.getObserver().asBinder()); data.writeStrongBinder( cancellationSignal != null ? cancellationSignal.asBinder() : null); mRemote.transact(IContentProvider.QUERY_TRANSACTION, data, reply, 0); DatabaseUtils.readExceptionFromParcel(reply); if (reply.readInt() != 0) { BulkCursorDescriptor d = BulkCursorDescriptor.CREATOR.createFromParcel(reply); Binder.copyAllowBlocking(mRemote, (d.cursor != null) ? d.cursor.asBinder() : null); adaptor.initialize(d); } else { adaptor.close(); adaptor = null; } return adaptor; } catch (RemoteException ex) { adaptor.close(); throw ex; } catch (RuntimeException ex) { adaptor.close(); throw ex; } finally { data.recycle(); reply.recycle(); } } @Override public String getType(AttributionSource attributionSource, Uri url) throws RemoteException { Parcel data = Parcel.obtain(); Parcel reply = Parcel.obtain(); try { data.writeInterfaceToken(IContentProvider.descriptor); attributionSource.writeToParcel(data, 0); url.writeToParcel(data, 0); mRemote.transact(IContentProvider.GET_TYPE_TRANSACTION, data, reply, 0); DatabaseUtils.readExceptionFromParcel(reply); String out = reply.readString(); return out; } finally { data.recycle(); reply.recycle(); } } @Override /* oneway */ public void getTypeAsync(AttributionSource attributionSource, Uri uri, RemoteCallback callback) throws RemoteException { Parcel data = Parcel.obtain(); try { data.writeInterfaceToken(IContentProvider.descriptor); attributionSource.writeToParcel(data, 0); uri.writeToParcel(data, 0); callback.writeToParcel(data, 0); mRemote.transact(IContentProvider.GET_TYPE_ASYNC_TRANSACTION, data, null, IBinder.FLAG_ONEWAY); } finally { data.recycle(); } } @Override /* oneway */ public void getTypeAnonymousAsync(Uri uri, RemoteCallback callback) throws RemoteException { Parcel data = Parcel.obtain(); try { data.writeInterfaceToken(IContentProvider.descriptor); uri.writeToParcel(data, 0); callback.writeToParcel(data, 0); mRemote.transact(IContentProvider.GET_TYPE_ANONYMOUS_ASYNC_TRANSACTION, data, null, IBinder.FLAG_ONEWAY); } finally { data.recycle(); } } @Override public Uri insert(@NonNull AttributionSource attributionSource, Uri url, ContentValues values, Bundle extras) throws RemoteException { Parcel data = Parcel.obtain(); Parcel reply = Parcel.obtain(); try { data.writeInterfaceToken(IContentProvider.descriptor); attributionSource.writeToParcel(data, 0); url.writeToParcel(data, 0); values.writeToParcel(data, 0); data.writeBundle(extras); mRemote.transact(IContentProvider.INSERT_TRANSACTION, data, reply, 0); DatabaseUtils.readExceptionFromParcel(reply); Uri out = Uri.CREATOR.createFromParcel(reply); return out; } finally { data.recycle(); reply.recycle(); } } @Override public int bulkInsert(@NonNull AttributionSource attributionSource, Uri url, ContentValues[] values) throws RemoteException { Parcel data = Parcel.obtain(); Parcel reply = Parcel.obtain(); try { data.writeInterfaceToken(IContentProvider.descriptor); attributionSource.writeToParcel(data, 0); url.writeToParcel(data, 0); data.writeTypedArray(values, 0); mRemote.transact(IContentProvider.BULK_INSERT_TRANSACTION, data, reply, 0); DatabaseUtils.readExceptionFromParcel(reply); int count = reply.readInt(); return count; } finally { data.recycle(); reply.recycle(); } } @Override public ContentProviderResult[] applyBatch(@NonNull AttributionSource attributionSource, String authority, ArrayList operations) throws RemoteException, OperationApplicationException { Parcel data = Parcel.obtain(); Parcel reply = Parcel.obtain(); try { data.writeInterfaceToken(IContentProvider.descriptor); attributionSource.writeToParcel(data, 0); data.writeString(authority); data.writeInt(operations.size()); for (ContentProviderOperation operation : operations) { operation.writeToParcel(data, 0); } mRemote.transact(IContentProvider.APPLY_BATCH_TRANSACTION, data, reply, 0); DatabaseUtils.readExceptionWithOperationApplicationExceptionFromParcel(reply); final ContentProviderResult[] results = reply.createTypedArray(ContentProviderResult.CREATOR); return results; } finally { data.recycle(); reply.recycle(); } } @Override public int delete(@NonNull AttributionSource attributionSource, Uri url, Bundle extras) throws RemoteException { Parcel data = Parcel.obtain(); Parcel reply = Parcel.obtain(); try { data.writeInterfaceToken(IContentProvider.descriptor); attributionSource.writeToParcel(data, 0); url.writeToParcel(data, 0); data.writeBundle(extras); mRemote.transact(IContentProvider.DELETE_TRANSACTION, data, reply, 0); DatabaseUtils.readExceptionFromParcel(reply); int count = reply.readInt(); return count; } finally { data.recycle(); reply.recycle(); } } @Override public int update(@NonNull AttributionSource attributionSource, Uri url, ContentValues values, Bundle extras) throws RemoteException { Parcel data = Parcel.obtain(); Parcel reply = Parcel.obtain(); try { data.writeInterfaceToken(IContentProvider.descriptor); attributionSource.writeToParcel(data, 0); url.writeToParcel(data, 0); values.writeToParcel(data, 0); data.writeBundle(extras); mRemote.transact(IContentProvider.UPDATE_TRANSACTION, data, reply, 0); DatabaseUtils.readExceptionFromParcel(reply); int count = reply.readInt(); return count; } finally { data.recycle(); reply.recycle(); } } @Override public ParcelFileDescriptor openFile(@NonNull AttributionSource attributionSource, Uri url, String mode, ICancellationSignal signal) throws RemoteException, FileNotFoundException { Parcel data = Parcel.obtain(); Parcel reply = Parcel.obtain(); try { data.writeInterfaceToken(IContentProvider.descriptor); attributionSource.writeToParcel(data, 0); url.writeToParcel(data, 0); data.writeString(mode); data.writeStrongBinder(signal != null ? signal.asBinder() : null); mRemote.transact(IContentProvider.OPEN_FILE_TRANSACTION, data, reply, 0); DatabaseUtils.readExceptionWithFileNotFoundExceptionFromParcel(reply); int has = reply.readInt(); ParcelFileDescriptor fd = has != 0 ? ParcelFileDescriptor.CREATOR .createFromParcel(reply) : null; return fd; } finally { data.recycle(); reply.recycle(); } } @Override public AssetFileDescriptor openAssetFile(@NonNull AttributionSource attributionSource, Uri url, String mode, ICancellationSignal signal) throws RemoteException, FileNotFoundException { Parcel data = Parcel.obtain(); Parcel reply = Parcel.obtain(); try { data.writeInterfaceToken(IContentProvider.descriptor); attributionSource.writeToParcel(data, 0); url.writeToParcel(data, 0); data.writeString(mode); data.writeStrongBinder(signal != null ? signal.asBinder() : null); mRemote.transact(IContentProvider.OPEN_ASSET_FILE_TRANSACTION, data, reply, 0); DatabaseUtils.readExceptionWithFileNotFoundExceptionFromParcel(reply); int has = reply.readInt(); AssetFileDescriptor fd = has != 0 ? AssetFileDescriptor.CREATOR.createFromParcel(reply) : null; return fd; } finally { data.recycle(); reply.recycle(); } } @Override public Bundle call(@NonNull AttributionSource attributionSource, String authority, String method, String request, Bundle extras) throws RemoteException { Parcel data = Parcel.obtain(); Parcel reply = Parcel.obtain(); try { data.writeInterfaceToken(IContentProvider.descriptor); attributionSource.writeToParcel(data, 0); data.writeString(authority); data.writeString(method); data.writeString(request); data.writeBundle(extras); mRemote.transact(IContentProvider.CALL_TRANSACTION, data, reply, 0); DatabaseUtils.readExceptionFromParcel(reply); Bundle bundle = reply.readBundle(); return bundle; } finally { data.recycle(); reply.recycle(); } } @Override public String[] getStreamTypes(AttributionSource attributionSource, Uri url, String mimeTypeFilter) throws RemoteException { Parcel data = Parcel.obtain(); Parcel reply = Parcel.obtain(); try { data.writeInterfaceToken(IContentProvider.descriptor); attributionSource.writeToParcel(data, 0); url.writeToParcel(data, 0); data.writeString(mimeTypeFilter); mRemote.transact(IContentProvider.GET_STREAM_TYPES_TRANSACTION, data, reply, 0); DatabaseUtils.readExceptionFromParcel(reply); String[] out = reply.createStringArray(); return out; } finally { data.recycle(); reply.recycle(); } } @Override public AssetFileDescriptor openTypedAssetFile(@NonNull AttributionSource attributionSource, Uri url, String mimeType, Bundle opts, ICancellationSignal signal) throws RemoteException, FileNotFoundException { Parcel data = Parcel.obtain(); Parcel reply = Parcel.obtain(); try { data.writeInterfaceToken(IContentProvider.descriptor); attributionSource.writeToParcel(data, 0); url.writeToParcel(data, 0); data.writeString(mimeType); data.writeBundle(opts); data.writeStrongBinder(signal != null ? signal.asBinder() : null); mRemote.transact(IContentProvider.OPEN_TYPED_ASSET_FILE_TRANSACTION, data, reply, 0); DatabaseUtils.readExceptionWithFileNotFoundExceptionFromParcel(reply); int has = reply.readInt(); AssetFileDescriptor fd = has != 0 ? AssetFileDescriptor.CREATOR.createFromParcel(reply) : null; return fd; } finally { data.recycle(); reply.recycle(); } } @Override public ICancellationSignal createCancellationSignal() throws RemoteException { Parcel data = Parcel.obtain(); Parcel reply = Parcel.obtain(); try { data.writeInterfaceToken(IContentProvider.descriptor); mRemote.transact(IContentProvider.CREATE_CANCELATION_SIGNAL_TRANSACTION, data, reply, 0); DatabaseUtils.readExceptionFromParcel(reply); ICancellationSignal cancellationSignal = ICancellationSignal.Stub.asInterface( reply.readStrongBinder()); return cancellationSignal; } finally { data.recycle(); reply.recycle(); } } @Override public Uri canonicalize(@NonNull AttributionSource attributionSource, Uri url) throws RemoteException { Parcel data = Parcel.obtain(); Parcel reply = Parcel.obtain(); try { data.writeInterfaceToken(IContentProvider.descriptor); attributionSource.writeToParcel(data, 0); 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(); } } @Override /* oneway */ public void canonicalizeAsync(@NonNull AttributionSource attributionSource, Uri uri, RemoteCallback callback) throws RemoteException { Parcel data = Parcel.obtain(); try { data.writeInterfaceToken(IContentProvider.descriptor); attributionSource.writeToParcel(data, 0); uri.writeToParcel(data, 0); callback.writeToParcel(data, 0); mRemote.transact(IContentProvider.CANONICALIZE_ASYNC_TRANSACTION, data, null, Binder.FLAG_ONEWAY); } finally { data.recycle(); } } @Override public Uri uncanonicalize(@NonNull AttributionSource attributionSource, Uri url) throws RemoteException { Parcel data = Parcel.obtain(); Parcel reply = Parcel.obtain(); try { data.writeInterfaceToken(IContentProvider.descriptor); attributionSource.writeToParcel(data, 0); 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(); } } @Override /* oneway */ public void uncanonicalizeAsync(@NonNull AttributionSource attributionSource, Uri uri, RemoteCallback callback) throws RemoteException { Parcel data = Parcel.obtain(); try { data.writeInterfaceToken(IContentProvider.descriptor); attributionSource.writeToParcel(data, 0); uri.writeToParcel(data, 0); callback.writeToParcel(data, 0); mRemote.transact(IContentProvider.UNCANONICALIZE_ASYNC_TRANSACTION, data, null, Binder.FLAG_ONEWAY); } finally { data.recycle(); } } @Override public boolean refresh(@NonNull AttributionSource attributionSource, Uri url, Bundle extras, ICancellationSignal signal) throws RemoteException { Parcel data = Parcel.obtain(); Parcel reply = Parcel.obtain(); try { data.writeInterfaceToken(IContentProvider.descriptor); attributionSource.writeToParcel(data, 0); url.writeToParcel(data, 0); data.writeBundle(extras); data.writeStrongBinder(signal != null ? signal.asBinder() : null); mRemote.transact(IContentProvider.REFRESH_TRANSACTION, data, reply, 0); DatabaseUtils.readExceptionFromParcel(reply); int success = reply.readInt(); return (success == 0); } finally { data.recycle(); reply.recycle(); } } @Override public int checkUriPermission(@NonNull AttributionSource attributionSource, Uri url, int uid, int modeFlags) throws RemoteException { Parcel data = Parcel.obtain(); Parcel reply = Parcel.obtain(); try { data.writeInterfaceToken(IContentProvider.descriptor); attributionSource.writeToParcel(data, 0); url.writeToParcel(data, 0); data.writeInt(uid); data.writeInt(modeFlags); mRemote.transact(IContentProvider.CHECK_URI_PERMISSION_TRANSACTION, data, reply, 0); DatabaseUtils.readExceptionFromParcel(reply); return reply.readInt(); } finally { data.recycle(); reply.recycle(); } } @UnsupportedAppUsage private IBinder mRemote; }