Home | History | Annotate | Download | only in content
      1 /*
      2  * Copyright (C) 2006 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 package android.content;
     18 
     19 import android.content.res.AssetFileDescriptor;
     20 import android.database.BulkCursorDescriptor;
     21 import android.database.BulkCursorToCursorAdaptor;
     22 import android.database.Cursor;
     23 import android.database.CursorToBulkCursorAdaptor;
     24 import android.database.DatabaseUtils;
     25 import android.database.IContentObserver;
     26 import android.net.Uri;
     27 import android.os.Binder;
     28 import android.os.Bundle;
     29 import android.os.IBinder;
     30 import android.os.ICancellationSignal;
     31 import android.os.Parcel;
     32 import android.os.ParcelFileDescriptor;
     33 import android.os.Parcelable;
     34 import android.os.RemoteException;
     35 
     36 import java.io.FileNotFoundException;
     37 import java.util.ArrayList;
     38 
     39 /**
     40  * {@hide}
     41  */
     42 abstract public class ContentProviderNative extends Binder implements IContentProvider {
     43     public ContentProviderNative()
     44     {
     45         attachInterface(this, descriptor);
     46     }
     47 
     48     /**
     49      * Cast a Binder object into a content resolver interface, generating
     50      * a proxy if needed.
     51      */
     52     static public IContentProvider asInterface(IBinder obj)
     53     {
     54         if (obj == null) {
     55             return null;
     56         }
     57         IContentProvider in =
     58             (IContentProvider)obj.queryLocalInterface(descriptor);
     59         if (in != null) {
     60             return in;
     61         }
     62 
     63         return new ContentProviderProxy(obj);
     64     }
     65 
     66     /**
     67      * Gets the name of the content provider.
     68      * Should probably be part of the {@link IContentProvider} interface.
     69      * @return The content provider name.
     70      */
     71     public abstract String getProviderName();
     72 
     73     @Override
     74     public boolean onTransact(int code, Parcel data, Parcel reply, int flags)
     75             throws RemoteException {
     76         try {
     77             switch (code) {
     78                 case QUERY_TRANSACTION:
     79                 {
     80                     data.enforceInterface(IContentProvider.descriptor);
     81 
     82                     String callingPkg = data.readString();
     83                     Uri url = Uri.CREATOR.createFromParcel(data);
     84 
     85                     // String[] projection
     86                     int num = data.readInt();
     87                     String[] projection = null;
     88                     if (num > 0) {
     89                         projection = new String[num];
     90                         for (int i = 0; i < num; i++) {
     91                             projection[i] = data.readString();
     92                         }
     93                     }
     94 
     95                     // String selection, String[] selectionArgs...
     96                     String selection = data.readString();
     97                     num = data.readInt();
     98                     String[] selectionArgs = null;
     99                     if (num > 0) {
    100                         selectionArgs = new String[num];
    101                         for (int i = 0; i < num; i++) {
    102                             selectionArgs[i] = data.readString();
    103                         }
    104                     }
    105 
    106                     String sortOrder = data.readString();
    107                     IContentObserver observer = IContentObserver.Stub.asInterface(
    108                             data.readStrongBinder());
    109                     ICancellationSignal cancellationSignal = ICancellationSignal.Stub.asInterface(
    110                             data.readStrongBinder());
    111 
    112                     Cursor cursor = query(callingPkg, url, projection, selection, selectionArgs,
    113                             sortOrder, cancellationSignal);
    114                     if (cursor != null) {
    115                         try {
    116                             CursorToBulkCursorAdaptor adaptor = new CursorToBulkCursorAdaptor(
    117                                     cursor, observer, getProviderName());
    118                             BulkCursorDescriptor d = adaptor.getBulkCursorDescriptor();
    119                             cursor = null;
    120 
    121                             reply.writeNoException();
    122                             reply.writeInt(1);
    123                             d.writeToParcel(reply, Parcelable.PARCELABLE_WRITE_RETURN_VALUE);
    124                         } finally {
    125                             // Close cursor if an exception was thrown while constructing the adaptor.
    126                             if (cursor != null) {
    127                                 cursor.close();
    128                             }
    129                         }
    130                     } else {
    131                         reply.writeNoException();
    132                         reply.writeInt(0);
    133                     }
    134 
    135                     return true;
    136                 }
    137 
    138                 case GET_TYPE_TRANSACTION:
    139                 {
    140                     data.enforceInterface(IContentProvider.descriptor);
    141                     Uri url = Uri.CREATOR.createFromParcel(data);
    142                     String type = getType(url);
    143                     reply.writeNoException();
    144                     reply.writeString(type);
    145 
    146                     return true;
    147                 }
    148 
    149                 case INSERT_TRANSACTION:
    150                 {
    151                     data.enforceInterface(IContentProvider.descriptor);
    152                     String callingPkg = data.readString();
    153                     Uri url = Uri.CREATOR.createFromParcel(data);
    154                     ContentValues values = ContentValues.CREATOR.createFromParcel(data);
    155 
    156                     Uri out = insert(callingPkg, url, values);
    157                     reply.writeNoException();
    158                     Uri.writeToParcel(reply, out);
    159                     return true;
    160                 }
    161 
    162                 case BULK_INSERT_TRANSACTION:
    163                 {
    164                     data.enforceInterface(IContentProvider.descriptor);
    165                     String callingPkg = data.readString();
    166                     Uri url = Uri.CREATOR.createFromParcel(data);
    167                     ContentValues[] values = data.createTypedArray(ContentValues.CREATOR);
    168 
    169                     int count = bulkInsert(callingPkg, url, values);
    170                     reply.writeNoException();
    171                     reply.writeInt(count);
    172                     return true;
    173                 }
    174 
    175                 case APPLY_BATCH_TRANSACTION:
    176                 {
    177                     data.enforceInterface(IContentProvider.descriptor);
    178                     String callingPkg = data.readString();
    179                     final int numOperations = data.readInt();
    180                     final ArrayList<ContentProviderOperation> operations =
    181                             new ArrayList<ContentProviderOperation>(numOperations);
    182                     for (int i = 0; i < numOperations; i++) {
    183                         operations.add(i, ContentProviderOperation.CREATOR.createFromParcel(data));
    184                     }
    185                     final ContentProviderResult[] results = applyBatch(callingPkg, operations);
    186                     reply.writeNoException();
    187                     reply.writeTypedArray(results, 0);
    188                     return true;
    189                 }
    190 
    191                 case DELETE_TRANSACTION:
    192                 {
    193                     data.enforceInterface(IContentProvider.descriptor);
    194                     String callingPkg = data.readString();
    195                     Uri url = Uri.CREATOR.createFromParcel(data);
    196                     String selection = data.readString();
    197                     String[] selectionArgs = data.readStringArray();
    198 
    199                     int count = delete(callingPkg, url, selection, selectionArgs);
    200 
    201                     reply.writeNoException();
    202                     reply.writeInt(count);
    203                     return true;
    204                 }
    205 
    206                 case UPDATE_TRANSACTION:
    207                 {
    208                     data.enforceInterface(IContentProvider.descriptor);
    209                     String callingPkg = data.readString();
    210                     Uri url = Uri.CREATOR.createFromParcel(data);
    211                     ContentValues values = ContentValues.CREATOR.createFromParcel(data);
    212                     String selection = data.readString();
    213                     String[] selectionArgs = data.readStringArray();
    214 
    215                     int count = update(callingPkg, url, values, selection, selectionArgs);
    216 
    217                     reply.writeNoException();
    218                     reply.writeInt(count);
    219                     return true;
    220                 }
    221 
    222                 case OPEN_FILE_TRANSACTION:
    223                 {
    224                     data.enforceInterface(IContentProvider.descriptor);
    225                     String callingPkg = data.readString();
    226                     Uri url = Uri.CREATOR.createFromParcel(data);
    227                     String mode = data.readString();
    228                     ICancellationSignal signal = ICancellationSignal.Stub.asInterface(
    229                             data.readStrongBinder());
    230 
    231                     ParcelFileDescriptor fd;
    232                     fd = openFile(callingPkg, url, mode, signal);
    233                     reply.writeNoException();
    234                     if (fd != null) {
    235                         reply.writeInt(1);
    236                         fd.writeToParcel(reply,
    237                                 Parcelable.PARCELABLE_WRITE_RETURN_VALUE);
    238                     } else {
    239                         reply.writeInt(0);
    240                     }
    241                     return true;
    242                 }
    243 
    244                 case OPEN_ASSET_FILE_TRANSACTION:
    245                 {
    246                     data.enforceInterface(IContentProvider.descriptor);
    247                     String callingPkg = data.readString();
    248                     Uri url = Uri.CREATOR.createFromParcel(data);
    249                     String mode = data.readString();
    250                     ICancellationSignal signal = ICancellationSignal.Stub.asInterface(
    251                             data.readStrongBinder());
    252 
    253                     AssetFileDescriptor fd;
    254                     fd = openAssetFile(callingPkg, url, mode, signal);
    255                     reply.writeNoException();
    256                     if (fd != null) {
    257                         reply.writeInt(1);
    258                         fd.writeToParcel(reply,
    259                                 Parcelable.PARCELABLE_WRITE_RETURN_VALUE);
    260                     } else {
    261                         reply.writeInt(0);
    262                     }
    263                     return true;
    264                 }
    265 
    266                 case CALL_TRANSACTION:
    267                 {
    268                     data.enforceInterface(IContentProvider.descriptor);
    269 
    270                     String callingPkg = data.readString();
    271                     String method = data.readString();
    272                     String stringArg = data.readString();
    273                     Bundle args = data.readBundle();
    274 
    275                     Bundle responseBundle = call(callingPkg, method, stringArg, args);
    276 
    277                     reply.writeNoException();
    278                     reply.writeBundle(responseBundle);
    279                     return true;
    280                 }
    281 
    282                 case GET_STREAM_TYPES_TRANSACTION:
    283                 {
    284                     data.enforceInterface(IContentProvider.descriptor);
    285                     Uri url = Uri.CREATOR.createFromParcel(data);
    286                     String mimeTypeFilter = data.readString();
    287                     String[] types = getStreamTypes(url, mimeTypeFilter);
    288                     reply.writeNoException();
    289                     reply.writeStringArray(types);
    290 
    291                     return true;
    292                 }
    293 
    294                 case OPEN_TYPED_ASSET_FILE_TRANSACTION:
    295                 {
    296                     data.enforceInterface(IContentProvider.descriptor);
    297                     String callingPkg = data.readString();
    298                     Uri url = Uri.CREATOR.createFromParcel(data);
    299                     String mimeType = data.readString();
    300                     Bundle opts = data.readBundle();
    301                     ICancellationSignal signal = ICancellationSignal.Stub.asInterface(
    302                             data.readStrongBinder());
    303 
    304                     AssetFileDescriptor fd;
    305                     fd = openTypedAssetFile(callingPkg, url, mimeType, opts, signal);
    306                     reply.writeNoException();
    307                     if (fd != null) {
    308                         reply.writeInt(1);
    309                         fd.writeToParcel(reply,
    310                                 Parcelable.PARCELABLE_WRITE_RETURN_VALUE);
    311                     } else {
    312                         reply.writeInt(0);
    313                     }
    314                     return true;
    315                 }
    316 
    317                 case CREATE_CANCELATION_SIGNAL_TRANSACTION:
    318                 {
    319                     data.enforceInterface(IContentProvider.descriptor);
    320 
    321                     ICancellationSignal cancellationSignal = createCancellationSignal();
    322                     reply.writeNoException();
    323                     reply.writeStrongBinder(cancellationSignal.asBinder());
    324                     return true;
    325                 }
    326 
    327                 case CANONICALIZE_TRANSACTION:
    328                 {
    329                     data.enforceInterface(IContentProvider.descriptor);
    330                     String callingPkg = data.readString();
    331                     Uri url = Uri.CREATOR.createFromParcel(data);
    332 
    333                     Uri out = canonicalize(callingPkg, url);
    334                     reply.writeNoException();
    335                     Uri.writeToParcel(reply, out);
    336                     return true;
    337                 }
    338 
    339                 case UNCANONICALIZE_TRANSACTION:
    340                 {
    341                     data.enforceInterface(IContentProvider.descriptor);
    342                     String callingPkg = data.readString();
    343                     Uri url = Uri.CREATOR.createFromParcel(data);
    344 
    345                     Uri out = uncanonicalize(callingPkg, url);
    346                     reply.writeNoException();
    347                     Uri.writeToParcel(reply, out);
    348                     return true;
    349                 }
    350             }
    351         } catch (Exception e) {
    352             DatabaseUtils.writeExceptionToParcel(reply, e);
    353             return true;
    354         }
    355 
    356         return super.onTransact(code, data, reply, flags);
    357     }
    358 
    359     public IBinder asBinder()
    360     {
    361         return this;
    362     }
    363 }
    364 
    365 
    366 final class ContentProviderProxy implements IContentProvider
    367 {
    368     public ContentProviderProxy(IBinder remote)
    369     {
    370         mRemote = remote;
    371     }
    372 
    373     public IBinder asBinder()
    374     {
    375         return mRemote;
    376     }
    377 
    378     public Cursor query(String callingPkg, Uri url, String[] projection, String selection,
    379             String[] selectionArgs, String sortOrder, ICancellationSignal cancellationSignal)
    380                     throws RemoteException {
    381         BulkCursorToCursorAdaptor adaptor = new BulkCursorToCursorAdaptor();
    382         Parcel data = Parcel.obtain();
    383         Parcel reply = Parcel.obtain();
    384         try {
    385             data.writeInterfaceToken(IContentProvider.descriptor);
    386 
    387             data.writeString(callingPkg);
    388             url.writeToParcel(data, 0);
    389             int length = 0;
    390             if (projection != null) {
    391                 length = projection.length;
    392             }
    393             data.writeInt(length);
    394             for (int i = 0; i < length; i++) {
    395                 data.writeString(projection[i]);
    396             }
    397             data.writeString(selection);
    398             if (selectionArgs != null) {
    399                 length = selectionArgs.length;
    400             } else {
    401                 length = 0;
    402             }
    403             data.writeInt(length);
    404             for (int i = 0; i < length; i++) {
    405                 data.writeString(selectionArgs[i]);
    406             }
    407             data.writeString(sortOrder);
    408             data.writeStrongBinder(adaptor.getObserver().asBinder());
    409             data.writeStrongBinder(cancellationSignal != null ? cancellationSignal.asBinder() : null);
    410 
    411             mRemote.transact(IContentProvider.QUERY_TRANSACTION, data, reply, 0);
    412 
    413             DatabaseUtils.readExceptionFromParcel(reply);
    414 
    415             if (reply.readInt() != 0) {
    416                 BulkCursorDescriptor d = BulkCursorDescriptor.CREATOR.createFromParcel(reply);
    417                 adaptor.initialize(d);
    418             } else {
    419                 adaptor.close();
    420                 adaptor = null;
    421             }
    422             return adaptor;
    423         } catch (RemoteException ex) {
    424             adaptor.close();
    425             throw ex;
    426         } catch (RuntimeException ex) {
    427             adaptor.close();
    428             throw ex;
    429         } finally {
    430             data.recycle();
    431             reply.recycle();
    432         }
    433     }
    434 
    435     public String getType(Uri url) throws RemoteException
    436     {
    437         Parcel data = Parcel.obtain();
    438         Parcel reply = Parcel.obtain();
    439         try {
    440             data.writeInterfaceToken(IContentProvider.descriptor);
    441 
    442             url.writeToParcel(data, 0);
    443 
    444             mRemote.transact(IContentProvider.GET_TYPE_TRANSACTION, data, reply, 0);
    445 
    446             DatabaseUtils.readExceptionFromParcel(reply);
    447             String out = reply.readString();
    448             return out;
    449         } finally {
    450             data.recycle();
    451             reply.recycle();
    452         }
    453     }
    454 
    455     public Uri insert(String callingPkg, Uri url, ContentValues values) throws RemoteException
    456     {
    457         Parcel data = Parcel.obtain();
    458         Parcel reply = Parcel.obtain();
    459         try {
    460             data.writeInterfaceToken(IContentProvider.descriptor);
    461 
    462             data.writeString(callingPkg);
    463             url.writeToParcel(data, 0);
    464             values.writeToParcel(data, 0);
    465 
    466             mRemote.transact(IContentProvider.INSERT_TRANSACTION, data, reply, 0);
    467 
    468             DatabaseUtils.readExceptionFromParcel(reply);
    469             Uri out = Uri.CREATOR.createFromParcel(reply);
    470             return out;
    471         } finally {
    472             data.recycle();
    473             reply.recycle();
    474         }
    475     }
    476 
    477     public int bulkInsert(String callingPkg, Uri url, ContentValues[] values) throws RemoteException {
    478         Parcel data = Parcel.obtain();
    479         Parcel reply = Parcel.obtain();
    480         try {
    481             data.writeInterfaceToken(IContentProvider.descriptor);
    482 
    483             data.writeString(callingPkg);
    484             url.writeToParcel(data, 0);
    485             data.writeTypedArray(values, 0);
    486 
    487             mRemote.transact(IContentProvider.BULK_INSERT_TRANSACTION, data, reply, 0);
    488 
    489             DatabaseUtils.readExceptionFromParcel(reply);
    490             int count = reply.readInt();
    491             return count;
    492         } finally {
    493             data.recycle();
    494             reply.recycle();
    495         }
    496     }
    497 
    498     public ContentProviderResult[] applyBatch(String callingPkg,
    499             ArrayList<ContentProviderOperation> operations)
    500                     throws RemoteException, OperationApplicationException {
    501         Parcel data = Parcel.obtain();
    502         Parcel reply = Parcel.obtain();
    503         try {
    504             data.writeInterfaceToken(IContentProvider.descriptor);
    505             data.writeString(callingPkg);
    506             data.writeInt(operations.size());
    507             for (ContentProviderOperation operation : operations) {
    508                 operation.writeToParcel(data, 0);
    509             }
    510             mRemote.transact(IContentProvider.APPLY_BATCH_TRANSACTION, data, reply, 0);
    511 
    512             DatabaseUtils.readExceptionWithOperationApplicationExceptionFromParcel(reply);
    513             final ContentProviderResult[] results =
    514                     reply.createTypedArray(ContentProviderResult.CREATOR);
    515             return results;
    516         } finally {
    517             data.recycle();
    518             reply.recycle();
    519         }
    520     }
    521 
    522     public int delete(String callingPkg, Uri url, String selection, String[] selectionArgs)
    523             throws RemoteException {
    524         Parcel data = Parcel.obtain();
    525         Parcel reply = Parcel.obtain();
    526         try {
    527             data.writeInterfaceToken(IContentProvider.descriptor);
    528 
    529             data.writeString(callingPkg);
    530             url.writeToParcel(data, 0);
    531             data.writeString(selection);
    532             data.writeStringArray(selectionArgs);
    533 
    534             mRemote.transact(IContentProvider.DELETE_TRANSACTION, data, reply, 0);
    535 
    536             DatabaseUtils.readExceptionFromParcel(reply);
    537             int count = reply.readInt();
    538             return count;
    539         } finally {
    540             data.recycle();
    541             reply.recycle();
    542         }
    543     }
    544 
    545     public int update(String callingPkg, Uri url, ContentValues values, String selection,
    546             String[] selectionArgs) throws RemoteException {
    547         Parcel data = Parcel.obtain();
    548         Parcel reply = Parcel.obtain();
    549         try {
    550             data.writeInterfaceToken(IContentProvider.descriptor);
    551 
    552             data.writeString(callingPkg);
    553             url.writeToParcel(data, 0);
    554             values.writeToParcel(data, 0);
    555             data.writeString(selection);
    556             data.writeStringArray(selectionArgs);
    557 
    558             mRemote.transact(IContentProvider.UPDATE_TRANSACTION, data, reply, 0);
    559 
    560             DatabaseUtils.readExceptionFromParcel(reply);
    561             int count = reply.readInt();
    562             return count;
    563         } finally {
    564             data.recycle();
    565             reply.recycle();
    566         }
    567     }
    568 
    569     @Override
    570     public ParcelFileDescriptor openFile(
    571             String callingPkg, Uri url, String mode, ICancellationSignal signal)
    572             throws RemoteException, FileNotFoundException {
    573         Parcel data = Parcel.obtain();
    574         Parcel reply = Parcel.obtain();
    575         try {
    576             data.writeInterfaceToken(IContentProvider.descriptor);
    577 
    578             data.writeString(callingPkg);
    579             url.writeToParcel(data, 0);
    580             data.writeString(mode);
    581             data.writeStrongBinder(signal != null ? signal.asBinder() : null);
    582 
    583             mRemote.transact(IContentProvider.OPEN_FILE_TRANSACTION, data, reply, 0);
    584 
    585             DatabaseUtils.readExceptionWithFileNotFoundExceptionFromParcel(reply);
    586             int has = reply.readInt();
    587             ParcelFileDescriptor fd = has != 0 ? reply.readFileDescriptor() : null;
    588             return fd;
    589         } finally {
    590             data.recycle();
    591             reply.recycle();
    592         }
    593     }
    594 
    595     @Override
    596     public AssetFileDescriptor openAssetFile(
    597             String callingPkg, Uri url, String mode, ICancellationSignal signal)
    598             throws RemoteException, FileNotFoundException {
    599         Parcel data = Parcel.obtain();
    600         Parcel reply = Parcel.obtain();
    601         try {
    602             data.writeInterfaceToken(IContentProvider.descriptor);
    603 
    604             data.writeString(callingPkg);
    605             url.writeToParcel(data, 0);
    606             data.writeString(mode);
    607             data.writeStrongBinder(signal != null ? signal.asBinder() : null);
    608 
    609             mRemote.transact(IContentProvider.OPEN_ASSET_FILE_TRANSACTION, data, reply, 0);
    610 
    611             DatabaseUtils.readExceptionWithFileNotFoundExceptionFromParcel(reply);
    612             int has = reply.readInt();
    613             AssetFileDescriptor fd = has != 0
    614                     ? AssetFileDescriptor.CREATOR.createFromParcel(reply) : null;
    615             return fd;
    616         } finally {
    617             data.recycle();
    618             reply.recycle();
    619         }
    620     }
    621 
    622     public Bundle call(String callingPkg, String method, String request, Bundle args)
    623             throws RemoteException {
    624         Parcel data = Parcel.obtain();
    625         Parcel reply = Parcel.obtain();
    626         try {
    627             data.writeInterfaceToken(IContentProvider.descriptor);
    628 
    629             data.writeString(callingPkg);
    630             data.writeString(method);
    631             data.writeString(request);
    632             data.writeBundle(args);
    633 
    634             mRemote.transact(IContentProvider.CALL_TRANSACTION, data, reply, 0);
    635 
    636             DatabaseUtils.readExceptionFromParcel(reply);
    637             Bundle bundle = reply.readBundle();
    638             return bundle;
    639         } finally {
    640             data.recycle();
    641             reply.recycle();
    642         }
    643     }
    644 
    645     public String[] getStreamTypes(Uri url, String mimeTypeFilter) throws RemoteException
    646     {
    647         Parcel data = Parcel.obtain();
    648         Parcel reply = Parcel.obtain();
    649         try {
    650             data.writeInterfaceToken(IContentProvider.descriptor);
    651 
    652             url.writeToParcel(data, 0);
    653             data.writeString(mimeTypeFilter);
    654 
    655             mRemote.transact(IContentProvider.GET_STREAM_TYPES_TRANSACTION, data, reply, 0);
    656 
    657             DatabaseUtils.readExceptionFromParcel(reply);
    658             String[] out = reply.createStringArray();
    659             return out;
    660         } finally {
    661             data.recycle();
    662             reply.recycle();
    663         }
    664     }
    665 
    666     @Override
    667     public AssetFileDescriptor openTypedAssetFile(String callingPkg, Uri url, String mimeType,
    668             Bundle opts, ICancellationSignal signal) throws RemoteException, FileNotFoundException {
    669         Parcel data = Parcel.obtain();
    670         Parcel reply = Parcel.obtain();
    671         try {
    672             data.writeInterfaceToken(IContentProvider.descriptor);
    673 
    674             data.writeString(callingPkg);
    675             url.writeToParcel(data, 0);
    676             data.writeString(mimeType);
    677             data.writeBundle(opts);
    678             data.writeStrongBinder(signal != null ? signal.asBinder() : null);
    679 
    680             mRemote.transact(IContentProvider.OPEN_TYPED_ASSET_FILE_TRANSACTION, data, reply, 0);
    681 
    682             DatabaseUtils.readExceptionWithFileNotFoundExceptionFromParcel(reply);
    683             int has = reply.readInt();
    684             AssetFileDescriptor fd = has != 0
    685                     ? AssetFileDescriptor.CREATOR.createFromParcel(reply) : null;
    686             return fd;
    687         } finally {
    688             data.recycle();
    689             reply.recycle();
    690         }
    691     }
    692 
    693     public ICancellationSignal createCancellationSignal() throws RemoteException {
    694         Parcel data = Parcel.obtain();
    695         Parcel reply = Parcel.obtain();
    696         try {
    697             data.writeInterfaceToken(IContentProvider.descriptor);
    698 
    699             mRemote.transact(IContentProvider.CREATE_CANCELATION_SIGNAL_TRANSACTION,
    700                     data, reply, 0);
    701 
    702             DatabaseUtils.readExceptionFromParcel(reply);
    703             ICancellationSignal cancellationSignal = ICancellationSignal.Stub.asInterface(
    704                     reply.readStrongBinder());
    705             return cancellationSignal;
    706         } finally {
    707             data.recycle();
    708             reply.recycle();
    709         }
    710     }
    711 
    712     public Uri canonicalize(String callingPkg, Uri url) throws RemoteException
    713     {
    714         Parcel data = Parcel.obtain();
    715         Parcel reply = Parcel.obtain();
    716         try {
    717             data.writeInterfaceToken(IContentProvider.descriptor);
    718 
    719             data.writeString(callingPkg);
    720             url.writeToParcel(data, 0);
    721 
    722             mRemote.transact(IContentProvider.CANONICALIZE_TRANSACTION, data, reply, 0);
    723 
    724             DatabaseUtils.readExceptionFromParcel(reply);
    725             Uri out = Uri.CREATOR.createFromParcel(reply);
    726             return out;
    727         } finally {
    728             data.recycle();
    729             reply.recycle();
    730         }
    731     }
    732 
    733     public Uri uncanonicalize(String callingPkg, Uri url) throws RemoteException {
    734         Parcel data = Parcel.obtain();
    735         Parcel reply = Parcel.obtain();
    736         try {
    737             data.writeInterfaceToken(IContentProvider.descriptor);
    738 
    739             data.writeString(callingPkg);
    740             url.writeToParcel(data, 0);
    741 
    742             mRemote.transact(IContentProvider.UNCANONICALIZE_TRANSACTION, data, reply, 0);
    743 
    744             DatabaseUtils.readExceptionFromParcel(reply);
    745             Uri out = Uri.CREATOR.createFromParcel(reply);
    746             return out;
    747         } finally {
    748             data.recycle();
    749             reply.recycle();
    750         }
    751     }
    752 
    753     private IBinder mRemote;
    754 }
    755