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