• 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.BulkCursorNative;
21 import android.database.BulkCursorToCursorAdaptor;
22 import android.database.Cursor;
23 import android.database.CursorWindow;
24 import android.database.DatabaseUtils;
25 import android.database.IBulkCursor;
26 import android.database.IContentObserver;
27 import android.net.Uri;
28 import android.os.Binder;
29 import android.os.Bundle;
30 import android.os.RemoteException;
31 import android.os.IBinder;
32 import android.os.Parcel;
33 import android.os.ParcelFileDescriptor;
34 import android.os.Parcelable;
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     private static final String TAG = "ContentProvider";
44 
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     @Override
onTransact(int code, Parcel data, Parcel reply, int flags)69     public boolean onTransact(int code, Parcel data, Parcel reply, int flags)
70             throws RemoteException {
71         try {
72             switch (code) {
73                 case QUERY_TRANSACTION:
74                 {
75                     data.enforceInterface(IContentProvider.descriptor);
76 
77                     Uri url = Uri.CREATOR.createFromParcel(data);
78 
79                     // String[] projection
80                     int num = data.readInt();
81                     String[] projection = null;
82                     if (num > 0) {
83                         projection = new String[num];
84                         for (int i = 0; i < num; i++) {
85                             projection[i] = data.readString();
86                         }
87                     }
88 
89                     // String selection, String[] selectionArgs...
90                     String selection = data.readString();
91                     num = data.readInt();
92                     String[] selectionArgs = null;
93                     if (num > 0) {
94                         selectionArgs = new String[num];
95                         for (int i = 0; i < num; i++) {
96                             selectionArgs[i] = data.readString();
97                         }
98                     }
99 
100                     String sortOrder = data.readString();
101                     IContentObserver observer = IContentObserver.Stub.
102                         asInterface(data.readStrongBinder());
103                     CursorWindow window = CursorWindow.CREATOR.createFromParcel(data);
104 
105                     // Flag for whether caller wants the number of
106                     // rows in the cursor and the position of the
107                     // "_id" column index (or -1 if non-existent)
108                     // Only to be returned if binder != null.
109                     boolean wantsCursorMetadata = data.readInt() != 0;
110 
111                     IBulkCursor bulkCursor = bulkQuery(url, projection, selection,
112                             selectionArgs, sortOrder, observer, window);
113                     reply.writeNoException();
114                     if (bulkCursor != null) {
115                         reply.writeStrongBinder(bulkCursor.asBinder());
116 
117                         if (wantsCursorMetadata) {
118                             reply.writeInt(bulkCursor.count());
119                             reply.writeInt(BulkCursorToCursorAdaptor.findRowIdColumnIndex(
120                                 bulkCursor.getColumnNames()));
121                         }
122                     } else {
123                         reply.writeStrongBinder(null);
124                     }
125 
126                     return true;
127                 }
128 
129                 case GET_TYPE_TRANSACTION:
130                 {
131                     data.enforceInterface(IContentProvider.descriptor);
132                     Uri url = Uri.CREATOR.createFromParcel(data);
133                     String type = getType(url);
134                     reply.writeNoException();
135                     reply.writeString(type);
136 
137                     return true;
138                 }
139 
140                 case INSERT_TRANSACTION:
141                 {
142                     data.enforceInterface(IContentProvider.descriptor);
143                     Uri url = Uri.CREATOR.createFromParcel(data);
144                     ContentValues values = ContentValues.CREATOR.createFromParcel(data);
145 
146                     Uri out = insert(url, values);
147                     reply.writeNoException();
148                     Uri.writeToParcel(reply, out);
149                     return true;
150                 }
151 
152                 case BULK_INSERT_TRANSACTION:
153                 {
154                     data.enforceInterface(IContentProvider.descriptor);
155                     Uri url = Uri.CREATOR.createFromParcel(data);
156                     ContentValues[] values = data.createTypedArray(ContentValues.CREATOR);
157 
158                     int count = bulkInsert(url, values);
159                     reply.writeNoException();
160                     reply.writeInt(count);
161                     return true;
162                 }
163 
164                 case APPLY_BATCH_TRANSACTION:
165                 {
166                     data.enforceInterface(IContentProvider.descriptor);
167                     final int numOperations = data.readInt();
168                     final ArrayList<ContentProviderOperation> operations =
169                             new ArrayList<ContentProviderOperation>(numOperations);
170                     for (int i = 0; i < numOperations; i++) {
171                         operations.add(i, ContentProviderOperation.CREATOR.createFromParcel(data));
172                     }
173                     final ContentProviderResult[] results = applyBatch(operations);
174                     reply.writeNoException();
175                     reply.writeTypedArray(results, 0);
176                     return true;
177                 }
178 
179                 case DELETE_TRANSACTION:
180                 {
181                     data.enforceInterface(IContentProvider.descriptor);
182                     Uri url = Uri.CREATOR.createFromParcel(data);
183                     String selection = data.readString();
184                     String[] selectionArgs = data.readStringArray();
185 
186                     int count = delete(url, selection, selectionArgs);
187 
188                     reply.writeNoException();
189                     reply.writeInt(count);
190                     return true;
191                 }
192 
193                 case UPDATE_TRANSACTION:
194                 {
195                     data.enforceInterface(IContentProvider.descriptor);
196                     Uri url = Uri.CREATOR.createFromParcel(data);
197                     ContentValues values = ContentValues.CREATOR.createFromParcel(data);
198                     String selection = data.readString();
199                     String[] selectionArgs = data.readStringArray();
200 
201                     int count = update(url, values, selection, selectionArgs);
202 
203                     reply.writeNoException();
204                     reply.writeInt(count);
205                     return true;
206                 }
207 
208                 case OPEN_FILE_TRANSACTION:
209                 {
210                     data.enforceInterface(IContentProvider.descriptor);
211                     Uri url = Uri.CREATOR.createFromParcel(data);
212                     String mode = data.readString();
213 
214                     ParcelFileDescriptor fd;
215                     fd = openFile(url, mode);
216                     reply.writeNoException();
217                     if (fd != null) {
218                         reply.writeInt(1);
219                         fd.writeToParcel(reply,
220                                 Parcelable.PARCELABLE_WRITE_RETURN_VALUE);
221                     } else {
222                         reply.writeInt(0);
223                     }
224                     return true;
225                 }
226 
227                 case OPEN_ASSET_FILE_TRANSACTION:
228                 {
229                     data.enforceInterface(IContentProvider.descriptor);
230                     Uri url = Uri.CREATOR.createFromParcel(data);
231                     String mode = data.readString();
232 
233                     AssetFileDescriptor fd;
234                     fd = openAssetFile(url, mode);
235                     reply.writeNoException();
236                     if (fd != null) {
237                         reply.writeInt(1);
238                         fd.writeToParcel(reply,
239                                 Parcelable.PARCELABLE_WRITE_RETURN_VALUE);
240                     } else {
241                         reply.writeInt(0);
242                     }
243                     return true;
244                 }
245 
246                 case CALL_TRANSACTION:
247                 {
248                     data.enforceInterface(IContentProvider.descriptor);
249 
250                     String method = data.readString();
251                     String stringArg = data.readString();
252                     Bundle args = data.readBundle();
253 
254                     Bundle responseBundle = call(method, stringArg, args);
255 
256                     reply.writeNoException();
257                     reply.writeBundle(responseBundle);
258                     return true;
259                 }
260             }
261         } catch (Exception e) {
262             DatabaseUtils.writeExceptionToParcel(reply, e);
263             return true;
264         }
265 
266         return super.onTransact(code, data, reply, flags);
267     }
268 
asBinder()269     public IBinder asBinder()
270     {
271         return this;
272     }
273 }
274 
275 
276 final class ContentProviderProxy implements IContentProvider
277 {
ContentProviderProxy(IBinder remote)278     public ContentProviderProxy(IBinder remote)
279     {
280         mRemote = remote;
281     }
282 
asBinder()283     public IBinder asBinder()
284     {
285         return mRemote;
286     }
287 
288     // Like bulkQuery() but sets up provided 'adaptor' if not null.
bulkQueryInternal( Uri url, String[] projection, String selection, String[] selectionArgs, String sortOrder, IContentObserver observer, CursorWindow window, BulkCursorToCursorAdaptor adaptor)289     private IBulkCursor bulkQueryInternal(
290         Uri url, String[] projection,
291         String selection, String[] selectionArgs, String sortOrder,
292         IContentObserver observer, CursorWindow window,
293         BulkCursorToCursorAdaptor adaptor) throws RemoteException {
294         Parcel data = Parcel.obtain();
295         Parcel reply = Parcel.obtain();
296 
297         data.writeInterfaceToken(IContentProvider.descriptor);
298 
299         url.writeToParcel(data, 0);
300         int length = 0;
301         if (projection != null) {
302             length = projection.length;
303         }
304         data.writeInt(length);
305         for (int i = 0; i < length; i++) {
306             data.writeString(projection[i]);
307         }
308         data.writeString(selection);
309         if (selectionArgs != null) {
310             length = selectionArgs.length;
311         } else {
312             length = 0;
313         }
314         data.writeInt(length);
315         for (int i = 0; i < length; i++) {
316             data.writeString(selectionArgs[i]);
317         }
318         data.writeString(sortOrder);
319         data.writeStrongBinder(observer.asBinder());
320         window.writeToParcel(data, 0);
321 
322         // Flag for whether or not we want the number of rows in the
323         // cursor and the position of the "_id" column index (or -1 if
324         // non-existent).  Only to be returned if binder != null.
325         final boolean wantsCursorMetadata = (adaptor != null);
326         data.writeInt(wantsCursorMetadata ? 1 : 0);
327 
328         mRemote.transact(IContentProvider.QUERY_TRANSACTION, data, reply, 0);
329 
330         DatabaseUtils.readExceptionFromParcel(reply);
331 
332         IBulkCursor bulkCursor = null;
333         IBinder bulkCursorBinder = reply.readStrongBinder();
334         if (bulkCursorBinder != null) {
335             bulkCursor = BulkCursorNative.asInterface(bulkCursorBinder);
336 
337             if (wantsCursorMetadata) {
338                 int rowCount = reply.readInt();
339                 int idColumnPosition = reply.readInt();
340                 if (bulkCursor != null) {
341                     adaptor.set(bulkCursor, rowCount, idColumnPosition);
342                 }
343             }
344         }
345 
346         data.recycle();
347         reply.recycle();
348 
349         return bulkCursor;
350     }
351 
bulkQuery(Uri url, String[] projection, String selection, String[] selectionArgs, String sortOrder, IContentObserver observer, CursorWindow window)352     public IBulkCursor bulkQuery(Uri url, String[] projection,
353             String selection, String[] selectionArgs, String sortOrder, IContentObserver observer,
354             CursorWindow window) throws RemoteException {
355         return bulkQueryInternal(
356             url, projection, selection, selectionArgs, sortOrder,
357             observer, window,
358             null /* BulkCursorToCursorAdaptor */);
359     }
360 
query(Uri url, String[] projection, String selection, String[] selectionArgs, String sortOrder)361     public Cursor query(Uri url, String[] projection, String selection,
362             String[] selectionArgs, String sortOrder) throws RemoteException {
363         //TODO make a pool of windows so we can reuse memory dealers
364         CursorWindow window = new CursorWindow(false /* window will be used remotely */);
365         BulkCursorToCursorAdaptor adaptor = new BulkCursorToCursorAdaptor();
366         IBulkCursor bulkCursor = bulkQueryInternal(
367             url, projection, selection, selectionArgs, sortOrder,
368             adaptor.getObserver(), window,
369             adaptor);
370         if (bulkCursor == null) {
371             return null;
372         }
373         return adaptor;
374     }
375 
getType(Uri url)376     public String getType(Uri url) throws RemoteException
377     {
378         Parcel data = Parcel.obtain();
379         Parcel reply = Parcel.obtain();
380 
381         data.writeInterfaceToken(IContentProvider.descriptor);
382 
383         url.writeToParcel(data, 0);
384 
385         mRemote.transact(IContentProvider.GET_TYPE_TRANSACTION, data, reply, 0);
386 
387         DatabaseUtils.readExceptionFromParcel(reply);
388         String out = reply.readString();
389 
390         data.recycle();
391         reply.recycle();
392 
393         return out;
394     }
395 
insert(Uri url, ContentValues values)396     public Uri insert(Uri url, ContentValues values) throws RemoteException
397     {
398         Parcel data = Parcel.obtain();
399         Parcel reply = Parcel.obtain();
400 
401         data.writeInterfaceToken(IContentProvider.descriptor);
402 
403         url.writeToParcel(data, 0);
404         values.writeToParcel(data, 0);
405 
406         mRemote.transact(IContentProvider.INSERT_TRANSACTION, data, reply, 0);
407 
408         DatabaseUtils.readExceptionFromParcel(reply);
409         Uri out = Uri.CREATOR.createFromParcel(reply);
410 
411         data.recycle();
412         reply.recycle();
413 
414         return out;
415     }
416 
bulkInsert(Uri url, ContentValues[] values)417     public int bulkInsert(Uri url, ContentValues[] values) throws RemoteException {
418         Parcel data = Parcel.obtain();
419         Parcel reply = Parcel.obtain();
420 
421         data.writeInterfaceToken(IContentProvider.descriptor);
422 
423         url.writeToParcel(data, 0);
424         data.writeTypedArray(values, 0);
425 
426         mRemote.transact(IContentProvider.BULK_INSERT_TRANSACTION, data, reply, 0);
427 
428         DatabaseUtils.readExceptionFromParcel(reply);
429         int count = reply.readInt();
430 
431         data.recycle();
432         reply.recycle();
433 
434         return count;
435     }
436 
applyBatch(ArrayList<ContentProviderOperation> operations)437     public ContentProviderResult[] applyBatch(ArrayList<ContentProviderOperation> operations)
438             throws RemoteException, OperationApplicationException {
439         Parcel data = Parcel.obtain();
440         Parcel reply = Parcel.obtain();
441 
442         data.writeInterfaceToken(IContentProvider.descriptor);
443         data.writeInt(operations.size());
444         for (ContentProviderOperation operation : operations) {
445             operation.writeToParcel(data, 0);
446         }
447         mRemote.transact(IContentProvider.APPLY_BATCH_TRANSACTION, data, reply, 0);
448 
449         DatabaseUtils.readExceptionWithOperationApplicationExceptionFromParcel(reply);
450         final ContentProviderResult[] results =
451                 reply.createTypedArray(ContentProviderResult.CREATOR);
452 
453         data.recycle();
454         reply.recycle();
455 
456         return results;
457     }
458 
delete(Uri url, String selection, String[] selectionArgs)459     public int delete(Uri url, String selection, String[] selectionArgs)
460             throws RemoteException {
461         Parcel data = Parcel.obtain();
462         Parcel reply = Parcel.obtain();
463 
464         data.writeInterfaceToken(IContentProvider.descriptor);
465 
466         url.writeToParcel(data, 0);
467         data.writeString(selection);
468         data.writeStringArray(selectionArgs);
469 
470         mRemote.transact(IContentProvider.DELETE_TRANSACTION, data, reply, 0);
471 
472         DatabaseUtils.readExceptionFromParcel(reply);
473         int count = reply.readInt();
474 
475         data.recycle();
476         reply.recycle();
477 
478         return count;
479     }
480 
update(Uri url, ContentValues values, String selection, String[] selectionArgs)481     public int update(Uri url, ContentValues values, String selection,
482             String[] selectionArgs) throws RemoteException {
483         Parcel data = Parcel.obtain();
484         Parcel reply = Parcel.obtain();
485 
486         data.writeInterfaceToken(IContentProvider.descriptor);
487 
488         url.writeToParcel(data, 0);
489         values.writeToParcel(data, 0);
490         data.writeString(selection);
491         data.writeStringArray(selectionArgs);
492 
493         mRemote.transact(IContentProvider.UPDATE_TRANSACTION, data, reply, 0);
494 
495         DatabaseUtils.readExceptionFromParcel(reply);
496         int count = reply.readInt();
497 
498         data.recycle();
499         reply.recycle();
500 
501         return count;
502     }
503 
openFile(Uri url, String mode)504     public ParcelFileDescriptor openFile(Uri url, String mode)
505             throws RemoteException, FileNotFoundException {
506         Parcel data = Parcel.obtain();
507         Parcel reply = Parcel.obtain();
508 
509         data.writeInterfaceToken(IContentProvider.descriptor);
510 
511         url.writeToParcel(data, 0);
512         data.writeString(mode);
513 
514         mRemote.transact(IContentProvider.OPEN_FILE_TRANSACTION, data, reply, 0);
515 
516         DatabaseUtils.readExceptionWithFileNotFoundExceptionFromParcel(reply);
517         int has = reply.readInt();
518         ParcelFileDescriptor fd = has != 0 ? reply.readFileDescriptor() : null;
519 
520         data.recycle();
521         reply.recycle();
522 
523         return fd;
524     }
525 
openAssetFile(Uri url, String mode)526     public AssetFileDescriptor openAssetFile(Uri url, String mode)
527             throws RemoteException, FileNotFoundException {
528         Parcel data = Parcel.obtain();
529         Parcel reply = Parcel.obtain();
530 
531         data.writeInterfaceToken(IContentProvider.descriptor);
532 
533         url.writeToParcel(data, 0);
534         data.writeString(mode);
535 
536         mRemote.transact(IContentProvider.OPEN_ASSET_FILE_TRANSACTION, data, reply, 0);
537 
538         DatabaseUtils.readExceptionWithFileNotFoundExceptionFromParcel(reply);
539         int has = reply.readInt();
540         AssetFileDescriptor fd = has != 0
541                 ? AssetFileDescriptor.CREATOR.createFromParcel(reply) : null;
542 
543         data.recycle();
544         reply.recycle();
545 
546         return fd;
547     }
548 
call(String method, String request, Bundle args)549     public Bundle call(String method, String request, Bundle args)
550             throws RemoteException {
551         Parcel data = Parcel.obtain();
552         Parcel reply = Parcel.obtain();
553 
554         data.writeInterfaceToken(IContentProvider.descriptor);
555 
556         data.writeString(method);
557         data.writeString(request);
558         data.writeBundle(args);
559 
560         mRemote.transact(IContentProvider.CALL_TRANSACTION, data, reply, 0);
561 
562         DatabaseUtils.readExceptionFromParcel(reply);
563         Bundle bundle = reply.readBundle();
564 
565         data.recycle();
566         reply.recycle();
567 
568         return bundle;
569     }
570 
571     private IBinder mRemote;
572 }
573