• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 {
ContentProviderNative()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      */
asInterface(IBinder obj)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      */
getProviderName()73     public abstract String getProviderName();
74 
75     @Override
onTransact(int code, Parcel data, Parcel reply, int flags)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 
asBinder()313     public IBinder asBinder()
314     {
315         return this;
316     }
317 }
318 
319 
320 final class ContentProviderProxy implements IContentProvider
321 {
ContentProviderProxy(IBinder remote)322     public ContentProviderProxy(IBinder remote)
323     {
324         mRemote = remote;
325     }
326 
asBinder()327     public IBinder asBinder()
328     {
329         return mRemote;
330     }
331 
query(Uri url, String[] projection, String selection, String[] selectionArgs, String sortOrder, ICancellationSignal cancellationSignal)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 
getType(Uri url)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 
insert(Uri url, ContentValues values)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 
bulkInsert(Uri url, ContentValues[] values)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 
applyBatch(ArrayList<ContentProviderOperation> operations)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 
delete(Uri url, String selection, String[] selectionArgs)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 
update(Uri url, ContentValues values, String selection, String[] selectionArgs)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 
openFile(Uri url, String mode)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 
openAssetFile(Uri url, String mode)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 
call(String method, String request, Bundle args)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 
getStreamTypes(Uri url, String mimeTypeFilter)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 
openTypedAssetFile(Uri url, String mimeType, Bundle opts)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 
createCancellationSignal()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