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