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