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.BulkCursorNative;
     22 import android.database.BulkCursorToCursorAdaptor;
     23 import android.database.Cursor;
     24 import android.database.CursorToBulkCursorAdaptor;
     25 import android.database.DatabaseUtils;
     26 import android.database.IBulkCursor;
     27 import android.database.IContentObserver;
     28 import android.net.Uri;
     29 import android.os.Binder;
     30 import android.os.Bundle;
     31 import android.os.RemoteException;
     32 import android.os.IBinder;
     33 import android.os.ICancellationSignal;
     34 import android.os.Parcel;
     35 import android.os.ParcelFileDescriptor;
     36 import android.os.Parcelable;
     37 
     38 import java.io.FileNotFoundException;
     39 import java.util.ArrayList;
     40 
     41 /**
     42  * {@hide}
     43  */
     44 abstract public class ContentProviderNative extends Binder implements IContentProvider {
     45     public ContentProviderNative()
     46     {
     47         attachInterface(this, descriptor);
     48     }
     49 
     50     /**
     51      * Cast a Binder object into a content resolver interface, generating
     52      * a proxy if needed.
     53      */
     54     static public IContentProvider asInterface(IBinder obj)
     55     {
     56         if (obj == null) {
     57             return null;
     58         }
     59         IContentProvider in =
     60             (IContentProvider)obj.queryLocalInterface(descriptor);
     61         if (in != null) {
     62             return in;
     63         }
     64 
     65         return new ContentProviderProxy(obj);
     66     }
     67 
     68     /**
     69      * Gets the name of the content provider.
     70      * Should probably be part of the {@link IContentProvider} interface.
     71      * @return The content provider name.
     72      */
     73     public abstract String getProviderName();
     74 
     75     @Override
     76     public boolean onTransact(int code, Parcel data, Parcel reply, int flags)
     77             throws RemoteException {
     78         try {
     79             switch (code) {
     80                 case QUERY_TRANSACTION:
     81                 {
     82                     data.enforceInterface(IContentProvider.descriptor);
     83 
     84                     Uri url = Uri.CREATOR.createFromParcel(data);
     85 
     86                     // String[] projection
     87                     int num = data.readInt();
     88                     String[] projection = null;
     89                     if (num > 0) {
     90                         projection = new String[num];
     91                         for (int i = 0; i < num; i++) {
     92                             projection[i] = data.readString();
     93                         }
     94                     }
     95 
     96                     // String selection, String[] selectionArgs...
     97                     String selection = data.readString();
     98                     num = data.readInt();
     99                     String[] selectionArgs = null;
    100                     if (num > 0) {
    101                         selectionArgs = new String[num];
    102                         for (int i = 0; i < num; i++) {
    103                             selectionArgs[i] = data.readString();
    104                         }
    105                     }
    106 
    107                     String sortOrder = data.readString();
    108                     IContentObserver observer = IContentObserver.Stub.asInterface(
    109                             data.readStrongBinder());
    110                     ICancellationSignal cancellationSignal = ICancellationSignal.Stub.asInterface(
    111                             data.readStrongBinder());
    112 
    113                     Cursor cursor = query(url, projection, selection, selectionArgs, sortOrder,
    114                             cancellationSignal);
    115                     if (cursor != null) {
    116                         CursorToBulkCursorAdaptor adaptor = new CursorToBulkCursorAdaptor(
    117                                 cursor, observer, getProviderName());
    118                         BulkCursorDescriptor d = adaptor.getBulkCursorDescriptor();
    119 
    120                         reply.writeNoException();
    121                         reply.writeInt(1);
    122                         d.writeToParcel(reply, Parcelable.PARCELABLE_WRITE_RETURN_VALUE);
    123                     } else {
    124                         reply.writeNoException();
    125                         reply.writeInt(0);
    126                     }
    127 
    128                     return true;
    129                 }
    130 
    131                 case GET_TYPE_TRANSACTION:
    132                 {
    133                     data.enforceInterface(IContentProvider.descriptor);
    134                     Uri url = Uri.CREATOR.createFromParcel(data);
    135                     String type = getType(url);
    136                     reply.writeNoException();
    137                     reply.writeString(type);
    138 
    139                     return true;
    140                 }
    141 
    142                 case INSERT_TRANSACTION:
    143                 {
    144                     data.enforceInterface(IContentProvider.descriptor);
    145                     Uri url = Uri.CREATOR.createFromParcel(data);
    146                     ContentValues values = ContentValues.CREATOR.createFromParcel(data);
    147 
    148                     Uri out = insert(url, values);
    149                     reply.writeNoException();
    150                     Uri.writeToParcel(reply, out);
    151                     return true;
    152                 }
    153 
    154                 case BULK_INSERT_TRANSACTION:
    155                 {
    156                     data.enforceInterface(IContentProvider.descriptor);
    157                     Uri url = Uri.CREATOR.createFromParcel(data);
    158                     ContentValues[] values = data.createTypedArray(ContentValues.CREATOR);
    159 
    160                     int count = bulkInsert(url, values);
    161                     reply.writeNoException();
    162                     reply.writeInt(count);
    163                     return true;
    164                 }
    165 
    166                 case APPLY_BATCH_TRANSACTION:
    167                 {
    168                     data.enforceInterface(IContentProvider.descriptor);
    169                     final int numOperations = data.readInt();
    170                     final ArrayList<ContentProviderOperation> operations =
    171                             new ArrayList<ContentProviderOperation>(numOperations);
    172                     for (int i = 0; i < numOperations; i++) {
    173                         operations.add(i, ContentProviderOperation.CREATOR.createFromParcel(data));
    174                     }
    175                     final ContentProviderResult[] results = applyBatch(operations);
    176                     reply.writeNoException();
    177                     reply.writeTypedArray(results, 0);
    178                     return true;
    179                 }
    180 
    181                 case DELETE_TRANSACTION:
    182                 {
    183                     data.enforceInterface(IContentProvider.descriptor);
    184                     Uri url = Uri.CREATOR.createFromParcel(data);
    185                     String selection = data.readString();
    186                     String[] selectionArgs = data.readStringArray();
    187 
    188                     int count = delete(url, selection, selectionArgs);
    189 
    190                     reply.writeNoException();
    191                     reply.writeInt(count);
    192                     return true;
    193                 }
    194 
    195                 case UPDATE_TRANSACTION:
    196                 {
    197                     data.enforceInterface(IContentProvider.descriptor);
    198                     Uri url = Uri.CREATOR.createFromParcel(data);
    199                     ContentValues values = ContentValues.CREATOR.createFromParcel(data);
    200                     String selection = data.readString();
    201                     String[] selectionArgs = data.readStringArray();
    202 
    203                     int count = update(url, values, selection, selectionArgs);
    204 
    205                     reply.writeNoException();
    206                     reply.writeInt(count);
    207                     return true;
    208                 }
    209 
    210                 case OPEN_FILE_TRANSACTION:
    211                 {
    212                     data.enforceInterface(IContentProvider.descriptor);
    213                     Uri url = Uri.CREATOR.createFromParcel(data);
    214                     String mode = data.readString();
    215 
    216                     ParcelFileDescriptor fd;
    217                     fd = openFile(url, mode);
    218                     reply.writeNoException();
    219                     if (fd != null) {
    220                         reply.writeInt(1);
    221                         fd.writeToParcel(reply,
    222                                 Parcelable.PARCELABLE_WRITE_RETURN_VALUE);
    223                     } else {
    224                         reply.writeInt(0);
    225                     }
    226                     return true;
    227                 }
    228 
    229                 case OPEN_ASSET_FILE_TRANSACTION:
    230                 {
    231                     data.enforceInterface(IContentProvider.descriptor);
    232                     Uri url = Uri.CREATOR.createFromParcel(data);
    233                     String mode = data.readString();
    234 
    235                     AssetFileDescriptor fd;
    236                     fd = openAssetFile(url, mode);
    237                     reply.writeNoException();
    238                     if (fd != null) {
    239                         reply.writeInt(1);
    240                         fd.writeToParcel(reply,
    241                                 Parcelable.PARCELABLE_WRITE_RETURN_VALUE);
    242                     } else {
    243                         reply.writeInt(0);
    244                     }
    245                     return true;
    246                 }
    247 
    248                 case CALL_TRANSACTION:
    249                 {
    250                     data.enforceInterface(IContentProvider.descriptor);
    251 
    252                     String method = data.readString();
    253                     String stringArg = data.readString();
    254                     Bundle args = data.readBundle();
    255 
    256                     Bundle responseBundle = call(method, stringArg, args);
    257 
    258                     reply.writeNoException();
    259                     reply.writeBundle(responseBundle);
    260                     return true;
    261                 }
    262 
    263                 case GET_STREAM_TYPES_TRANSACTION:
    264                 {
    265                     data.enforceInterface(IContentProvider.descriptor);
    266                     Uri url = Uri.CREATOR.createFromParcel(data);
    267                     String mimeTypeFilter = data.readString();
    268                     String[] types = getStreamTypes(url, mimeTypeFilter);
    269                     reply.writeNoException();
    270                     reply.writeStringArray(types);
    271 
    272                     return true;
    273                 }
    274 
    275                 case OPEN_TYPED_ASSET_FILE_TRANSACTION:
    276                 {
    277                     data.enforceInterface(IContentProvider.descriptor);
    278                     Uri url = Uri.CREATOR.createFromParcel(data);
    279                     String mimeType = data.readString();
    280                     Bundle opts = data.readBundle();
    281 
    282                     AssetFileDescriptor fd;
    283                     fd = openTypedAssetFile(url, mimeType, opts);
    284                     reply.writeNoException();
    285                     if (fd != null) {
    286                         reply.writeInt(1);
    287                         fd.writeToParcel(reply,
    288                                 Parcelable.PARCELABLE_WRITE_RETURN_VALUE);
    289                     } else {
    290                         reply.writeInt(0);
    291                     }
    292                     return true;
    293                 }
    294 
    295                 case CREATE_CANCELATION_SIGNAL_TRANSACTION:
    296                 {
    297                     data.enforceInterface(IContentProvider.descriptor);
    298 
    299                     ICancellationSignal cancellationSignal = createCancellationSignal();
    300                     reply.writeNoException();
    301                     reply.writeStrongBinder(cancellationSignal.asBinder());
    302                     return true;
    303                 }
    304             }
    305         } catch (Exception e) {
    306             DatabaseUtils.writeExceptionToParcel(reply, e);
    307             return true;
    308         }
    309 
    310         return super.onTransact(code, data, reply, flags);
    311     }
    312 
    313     public IBinder asBinder()
    314     {
    315         return this;
    316     }
    317 }
    318 
    319 
    320 final class ContentProviderProxy implements IContentProvider
    321 {
    322     public ContentProviderProxy(IBinder remote)
    323     {
    324         mRemote = remote;
    325     }
    326 
    327     public IBinder asBinder()
    328     {
    329         return mRemote;
    330     }
    331 
    332     public Cursor query(Uri url, String[] projection, String selection,
    333             String[] selectionArgs, String sortOrder, ICancellationSignal cancellationSignal)
    334                     throws RemoteException {
    335         BulkCursorToCursorAdaptor adaptor = new BulkCursorToCursorAdaptor();
    336         Parcel data = Parcel.obtain();
    337         Parcel reply = Parcel.obtain();
    338         try {
    339             data.writeInterfaceToken(IContentProvider.descriptor);
    340 
    341             url.writeToParcel(data, 0);
    342             int length = 0;
    343             if (projection != null) {
    344                 length = projection.length;
    345             }
    346             data.writeInt(length);
    347             for (int i = 0; i < length; i++) {
    348                 data.writeString(projection[i]);
    349             }
    350             data.writeString(selection);
    351             if (selectionArgs != null) {
    352                 length = selectionArgs.length;
    353             } else {
    354                 length = 0;
    355             }
    356             data.writeInt(length);
    357             for (int i = 0; i < length; i++) {
    358                 data.writeString(selectionArgs[i]);
    359             }
    360             data.writeString(sortOrder);
    361             data.writeStrongBinder(adaptor.getObserver().asBinder());
    362             data.writeStrongBinder(cancellationSignal != null ? cancellationSignal.asBinder() : null);
    363 
    364             mRemote.transact(IContentProvider.QUERY_TRANSACTION, data, reply, 0);
    365 
    366             DatabaseUtils.readExceptionFromParcel(reply);
    367 
    368             if (reply.readInt() != 0) {
    369                 BulkCursorDescriptor d = BulkCursorDescriptor.CREATOR.createFromParcel(reply);
    370                 adaptor.initialize(d);
    371             } else {
    372                 adaptor.close();
    373                 adaptor = null;
    374             }
    375             return adaptor;
    376         } catch (RemoteException ex) {
    377             adaptor.close();
    378             throw ex;
    379         } catch (RuntimeException ex) {
    380             adaptor.close();
    381             throw ex;
    382         } finally {
    383             data.recycle();
    384             reply.recycle();
    385         }
    386     }
    387 
    388     public String getType(Uri url) throws RemoteException
    389     {
    390         Parcel data = Parcel.obtain();
    391         Parcel reply = Parcel.obtain();
    392         try {
    393             data.writeInterfaceToken(IContentProvider.descriptor);
    394 
    395             url.writeToParcel(data, 0);
    396 
    397             mRemote.transact(IContentProvider.GET_TYPE_TRANSACTION, data, reply, 0);
    398 
    399             DatabaseUtils.readExceptionFromParcel(reply);
    400             String out = reply.readString();
    401             return out;
    402         } finally {
    403             data.recycle();
    404             reply.recycle();
    405         }
    406     }
    407 
    408     public Uri insert(Uri url, ContentValues values) throws RemoteException
    409     {
    410         Parcel data = Parcel.obtain();
    411         Parcel reply = Parcel.obtain();
    412         try {
    413             data.writeInterfaceToken(IContentProvider.descriptor);
    414 
    415             url.writeToParcel(data, 0);
    416             values.writeToParcel(data, 0);
    417 
    418             mRemote.transact(IContentProvider.INSERT_TRANSACTION, data, reply, 0);
    419 
    420             DatabaseUtils.readExceptionFromParcel(reply);
    421             Uri out = Uri.CREATOR.createFromParcel(reply);
    422             return out;
    423         } finally {
    424             data.recycle();
    425             reply.recycle();
    426         }
    427     }
    428 
    429     public int bulkInsert(Uri url, ContentValues[] values) throws RemoteException {
    430         Parcel data = Parcel.obtain();
    431         Parcel reply = Parcel.obtain();
    432         try {
    433             data.writeInterfaceToken(IContentProvider.descriptor);
    434 
    435             url.writeToParcel(data, 0);
    436             data.writeTypedArray(values, 0);
    437 
    438             mRemote.transact(IContentProvider.BULK_INSERT_TRANSACTION, data, reply, 0);
    439 
    440             DatabaseUtils.readExceptionFromParcel(reply);
    441             int count = reply.readInt();
    442             return count;
    443         } finally {
    444             data.recycle();
    445             reply.recycle();
    446         }
    447     }
    448 
    449     public ContentProviderResult[] applyBatch(ArrayList<ContentProviderOperation> operations)
    450             throws RemoteException, OperationApplicationException {
    451         Parcel data = Parcel.obtain();
    452         Parcel reply = Parcel.obtain();
    453         try {
    454             data.writeInterfaceToken(IContentProvider.descriptor);
    455             data.writeInt(operations.size());
    456             for (ContentProviderOperation operation : operations) {
    457                 operation.writeToParcel(data, 0);
    458             }
    459             mRemote.transact(IContentProvider.APPLY_BATCH_TRANSACTION, data, reply, 0);
    460 
    461             DatabaseUtils.readExceptionWithOperationApplicationExceptionFromParcel(reply);
    462             final ContentProviderResult[] results =
    463                     reply.createTypedArray(ContentProviderResult.CREATOR);
    464             return results;
    465         } finally {
    466             data.recycle();
    467             reply.recycle();
    468         }
    469     }
    470 
    471     public int delete(Uri url, String selection, String[] selectionArgs)
    472             throws RemoteException {
    473         Parcel data = Parcel.obtain();
    474         Parcel reply = Parcel.obtain();
    475         try {
    476             data.writeInterfaceToken(IContentProvider.descriptor);
    477 
    478             url.writeToParcel(data, 0);
    479             data.writeString(selection);
    480             data.writeStringArray(selectionArgs);
    481 
    482             mRemote.transact(IContentProvider.DELETE_TRANSACTION, data, reply, 0);
    483 
    484             DatabaseUtils.readExceptionFromParcel(reply);
    485             int count = reply.readInt();
    486             return count;
    487         } finally {
    488             data.recycle();
    489             reply.recycle();
    490         }
    491     }
    492 
    493     public int update(Uri url, ContentValues values, String selection,
    494             String[] selectionArgs) throws RemoteException {
    495         Parcel data = Parcel.obtain();
    496         Parcel reply = Parcel.obtain();
    497         try {
    498             data.writeInterfaceToken(IContentProvider.descriptor);
    499 
    500             url.writeToParcel(data, 0);
    501             values.writeToParcel(data, 0);
    502             data.writeString(selection);
    503             data.writeStringArray(selectionArgs);
    504 
    505             mRemote.transact(IContentProvider.UPDATE_TRANSACTION, data, reply, 0);
    506 
    507             DatabaseUtils.readExceptionFromParcel(reply);
    508             int count = reply.readInt();
    509             return count;
    510         } finally {
    511             data.recycle();
    512             reply.recycle();
    513         }
    514     }
    515 
    516     public ParcelFileDescriptor openFile(Uri url, String mode)
    517             throws RemoteException, FileNotFoundException {
    518         Parcel data = Parcel.obtain();
    519         Parcel reply = Parcel.obtain();
    520         try {
    521             data.writeInterfaceToken(IContentProvider.descriptor);
    522 
    523             url.writeToParcel(data, 0);
    524             data.writeString(mode);
    525 
    526             mRemote.transact(IContentProvider.OPEN_FILE_TRANSACTION, data, reply, 0);
    527 
    528             DatabaseUtils.readExceptionWithFileNotFoundExceptionFromParcel(reply);
    529             int has = reply.readInt();
    530             ParcelFileDescriptor fd = has != 0 ? reply.readFileDescriptor() : null;
    531             return fd;
    532         } finally {
    533             data.recycle();
    534             reply.recycle();
    535         }
    536     }
    537 
    538     public AssetFileDescriptor openAssetFile(Uri url, String mode)
    539             throws RemoteException, FileNotFoundException {
    540         Parcel data = Parcel.obtain();
    541         Parcel reply = Parcel.obtain();
    542         try {
    543             data.writeInterfaceToken(IContentProvider.descriptor);
    544 
    545             url.writeToParcel(data, 0);
    546             data.writeString(mode);
    547 
    548             mRemote.transact(IContentProvider.OPEN_ASSET_FILE_TRANSACTION, data, reply, 0);
    549 
    550             DatabaseUtils.readExceptionWithFileNotFoundExceptionFromParcel(reply);
    551             int has = reply.readInt();
    552             AssetFileDescriptor fd = has != 0
    553                     ? AssetFileDescriptor.CREATOR.createFromParcel(reply) : null;
    554             return fd;
    555         } finally {
    556             data.recycle();
    557             reply.recycle();
    558         }
    559     }
    560 
    561     public Bundle call(String method, String request, Bundle args)
    562             throws RemoteException {
    563         Parcel data = Parcel.obtain();
    564         Parcel reply = Parcel.obtain();
    565         try {
    566             data.writeInterfaceToken(IContentProvider.descriptor);
    567 
    568             data.writeString(method);
    569             data.writeString(request);
    570             data.writeBundle(args);
    571 
    572             mRemote.transact(IContentProvider.CALL_TRANSACTION, data, reply, 0);
    573 
    574             DatabaseUtils.readExceptionFromParcel(reply);
    575             Bundle bundle = reply.readBundle();
    576             return bundle;
    577         } finally {
    578             data.recycle();
    579             reply.recycle();
    580         }
    581     }
    582 
    583     public String[] getStreamTypes(Uri url, String mimeTypeFilter) throws RemoteException
    584     {
    585         Parcel data = Parcel.obtain();
    586         Parcel reply = Parcel.obtain();
    587         try {
    588             data.writeInterfaceToken(IContentProvider.descriptor);
    589 
    590             url.writeToParcel(data, 0);
    591             data.writeString(mimeTypeFilter);
    592 
    593             mRemote.transact(IContentProvider.GET_STREAM_TYPES_TRANSACTION, data, reply, 0);
    594 
    595             DatabaseUtils.readExceptionFromParcel(reply);
    596             String[] out = reply.createStringArray();
    597             return out;
    598         } finally {
    599             data.recycle();
    600             reply.recycle();
    601         }
    602     }
    603 
    604     public AssetFileDescriptor openTypedAssetFile(Uri url, String mimeType, Bundle opts)
    605             throws RemoteException, FileNotFoundException {
    606         Parcel data = Parcel.obtain();
    607         Parcel reply = Parcel.obtain();
    608         try {
    609             data.writeInterfaceToken(IContentProvider.descriptor);
    610 
    611             url.writeToParcel(data, 0);
    612             data.writeString(mimeType);
    613             data.writeBundle(opts);
    614 
    615             mRemote.transact(IContentProvider.OPEN_TYPED_ASSET_FILE_TRANSACTION, data, reply, 0);
    616 
    617             DatabaseUtils.readExceptionWithFileNotFoundExceptionFromParcel(reply);
    618             int has = reply.readInt();
    619             AssetFileDescriptor fd = has != 0
    620                     ? AssetFileDescriptor.CREATOR.createFromParcel(reply) : null;
    621             return fd;
    622         } finally {
    623             data.recycle();
    624             reply.recycle();
    625         }
    626     }
    627 
    628     public ICancellationSignal createCancellationSignal() throws RemoteException {
    629         Parcel data = Parcel.obtain();
    630         Parcel reply = Parcel.obtain();
    631         try {
    632             data.writeInterfaceToken(IContentProvider.descriptor);
    633 
    634             mRemote.transact(IContentProvider.CREATE_CANCELATION_SIGNAL_TRANSACTION,
    635                     data, reply, 0);
    636 
    637             DatabaseUtils.readExceptionFromParcel(reply);
    638             ICancellationSignal cancellationSignal = ICancellationSignal.Stub.asInterface(
    639                     reply.readStrongBinder());
    640             return cancellationSignal;
    641         } finally {
    642             data.recycle();
    643             reply.recycle();
    644         }
    645     }
    646 
    647     private IBinder mRemote;
    648 }
    649