ContentProviderNative.java revision 6a8d5332f00bdfade6674b312e7166940aa28348
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 BULK_INSERT_ENTITIES_TRANSACTION:
158                {
159                    data.enforceInterface(IContentProvider.descriptor);
160                    Uri uri = Uri.CREATOR.createFromParcel(data);
161                    String className = data.readString();
162                    Class entityClass = Class.forName(className);
163                    int numEntities = data.readInt();
164                    Entity[] entities = new Entity[numEntities];
165                    for (int i = 0; i < numEntities; i++) {
166                        entities[i] = (Entity) data.readParcelable(entityClass.getClassLoader());
167                    }
168                    Uri[] uris = bulkInsertEntities(uri, entities);
169                    reply.writeNoException();
170                    reply.writeTypedArray(uris, 0);
171                    return true;
172                }
173
174                case BULK_UPDATE_ENTITIES_TRANSACTION:
175                {
176                    data.enforceInterface(IContentProvider.descriptor);
177                    Uri uri = Uri.CREATOR.createFromParcel(data);
178                    String className = data.readString();
179                    Class entityClass = Class.forName(className);
180                    int numEntities = data.readInt();
181                    Entity[] entities = new Entity[numEntities];
182                    for (int i = 0; i < numEntities; i++) {
183                        entities[i] = (Entity) data.readParcelable(entityClass.getClassLoader());
184                    }
185                    int[] counts = bulkUpdateEntities(uri, entities);
186                    reply.writeNoException();
187                    reply.writeIntArray(counts);
188                    return true;
189                }
190
191                case DELETE_TRANSACTION:
192                {
193                    data.enforceInterface(IContentProvider.descriptor);
194                    Uri url = Uri.CREATOR.createFromParcel(data);
195                    String selection = data.readString();
196                    String[] selectionArgs = data.readStringArray();
197
198                    int count = delete(url, selection, selectionArgs);
199
200                    reply.writeNoException();
201                    reply.writeInt(count);
202                    return true;
203                }
204
205                case UPDATE_TRANSACTION:
206                {
207                    data.enforceInterface(IContentProvider.descriptor);
208                    Uri url = Uri.CREATOR.createFromParcel(data);
209                    ContentValues values = ContentValues.CREATOR.createFromParcel(data);
210                    String selection = data.readString();
211                    String[] selectionArgs = data.readStringArray();
212
213                    int count = update(url, values, selection, selectionArgs);
214
215                    reply.writeNoException();
216                    reply.writeInt(count);
217                    return true;
218                }
219
220                case OPEN_FILE_TRANSACTION:
221                {
222                    data.enforceInterface(IContentProvider.descriptor);
223                    Uri url = Uri.CREATOR.createFromParcel(data);
224                    String mode = data.readString();
225
226                    ParcelFileDescriptor fd;
227                    fd = openFile(url, mode);
228                    reply.writeNoException();
229                    if (fd != null) {
230                        reply.writeInt(1);
231                        fd.writeToParcel(reply,
232                                Parcelable.PARCELABLE_WRITE_RETURN_VALUE);
233                    } else {
234                        reply.writeInt(0);
235                    }
236                    return true;
237                }
238
239                case OPEN_ASSET_FILE_TRANSACTION:
240                {
241                    data.enforceInterface(IContentProvider.descriptor);
242                    Uri url = Uri.CREATOR.createFromParcel(data);
243                    String mode = data.readString();
244
245                    AssetFileDescriptor fd;
246                    fd = openAssetFile(url, mode);
247                    reply.writeNoException();
248                    if (fd != null) {
249                        reply.writeInt(1);
250                        fd.writeToParcel(reply,
251                                Parcelable.PARCELABLE_WRITE_RETURN_VALUE);
252                    } else {
253                        reply.writeInt(0);
254                    }
255                    return true;
256                }
257            }
258        } catch (Exception e) {
259            DatabaseUtils.writeExceptionToParcel(reply, e);
260            return true;
261        }
262
263        return super.onTransact(code, data, reply, flags);
264    }
265
266    private class IEntityIteratorImpl extends IEntityIterator.Stub {
267        private final EntityIterator mEntityIterator;
268
269        IEntityIteratorImpl(EntityIterator iterator) {
270            mEntityIterator = iterator;
271        }
272        public boolean hasNext() throws RemoteException {
273            return mEntityIterator.hasNext();
274        }
275
276        public Entity next() throws RemoteException {
277            return mEntityIterator.next();
278        }
279
280        public void close() throws RemoteException {
281            mEntityIterator.close();
282        }
283    }
284
285    public IBinder asBinder()
286    {
287        return this;
288    }
289}
290
291
292final class ContentProviderProxy implements IContentProvider
293{
294    public ContentProviderProxy(IBinder remote)
295    {
296        mRemote = remote;
297    }
298
299    public IBinder asBinder()
300    {
301        return mRemote;
302    }
303
304    public IBulkCursor bulkQuery(Uri url, String[] projection,
305            String selection, String[] selectionArgs, String sortOrder, IContentObserver observer,
306            CursorWindow window) throws RemoteException {
307        Parcel data = Parcel.obtain();
308        Parcel reply = Parcel.obtain();
309
310        data.writeInterfaceToken(IContentProvider.descriptor);
311
312        url.writeToParcel(data, 0);
313        int length = 0;
314        if (projection != null) {
315            length = projection.length;
316        }
317        data.writeInt(length);
318        for (int i = 0; i < length; i++) {
319            data.writeString(projection[i]);
320        }
321        data.writeString(selection);
322        if (selectionArgs != null) {
323            length = selectionArgs.length;
324        } else {
325            length = 0;
326        }
327        data.writeInt(length);
328        for (int i = 0; i < length; i++) {
329            data.writeString(selectionArgs[i]);
330        }
331        data.writeString(sortOrder);
332        data.writeStrongBinder(observer.asBinder());
333        window.writeToParcel(data, 0);
334
335        mRemote.transact(IContentProvider.QUERY_TRANSACTION, data, reply, 0);
336
337        DatabaseUtils.readExceptionFromParcel(reply);
338
339        IBulkCursor bulkCursor = null;
340        IBinder bulkCursorBinder = reply.readStrongBinder();
341        if (bulkCursorBinder != null) {
342            bulkCursor = BulkCursorNative.asInterface(bulkCursorBinder);
343        }
344
345        data.recycle();
346        reply.recycle();
347
348        return bulkCursor;
349    }
350
351    public Cursor query(Uri url, String[] projection, String selection,
352            String[] selectionArgs, String sortOrder) throws RemoteException {
353        //TODO make a pool of windows so we can reuse memory dealers
354        CursorWindow window = new CursorWindow(false /* window will be used remotely */);
355        BulkCursorToCursorAdaptor adaptor = new BulkCursorToCursorAdaptor();
356        IBulkCursor bulkCursor = bulkQuery(url, projection, selection, selectionArgs, sortOrder,
357                adaptor.getObserver(), window);
358
359        if (bulkCursor == null) {
360            return null;
361        }
362        adaptor.set(bulkCursor);
363        return adaptor;
364    }
365
366    public EntityIterator queryEntities(Uri url, String selection, String[] selectionArgs,
367            String sortOrder)
368            throws RemoteException {
369        Parcel data = Parcel.obtain();
370        Parcel reply = Parcel.obtain();
371
372        data.writeInterfaceToken(IContentProvider.descriptor);
373
374        url.writeToParcel(data, 0);
375        data.writeString(selection);
376        data.writeStringArray(selectionArgs);
377        data.writeString(sortOrder);
378
379        mRemote.transact(IContentProvider.QUERY_ENTITIES_TRANSACTION, data, reply, 0);
380
381        DatabaseUtils.readExceptionFromParcel(reply);
382
383        IBinder entityIteratorBinder = reply.readStrongBinder();
384
385        data.recycle();
386        reply.recycle();
387
388        return new RemoteEntityIterator(IEntityIterator.Stub.asInterface(entityIteratorBinder));
389    }
390
391    static class RemoteEntityIterator implements EntityIterator {
392        private final IEntityIterator mEntityIterator;
393        RemoteEntityIterator(IEntityIterator entityIterator) {
394            mEntityIterator = entityIterator;
395        }
396
397        public boolean hasNext() throws RemoteException {
398            return mEntityIterator.hasNext();
399        }
400
401        public Entity next() throws RemoteException {
402            return mEntityIterator.next();
403        }
404
405        public void close() {
406            try {
407                mEntityIterator.close();
408            } catch (RemoteException e) {
409                // doesn't matter
410            }
411        }
412    }
413
414    public String getType(Uri url) throws RemoteException
415    {
416        Parcel data = Parcel.obtain();
417        Parcel reply = Parcel.obtain();
418
419        data.writeInterfaceToken(IContentProvider.descriptor);
420
421        url.writeToParcel(data, 0);
422
423        mRemote.transact(IContentProvider.GET_TYPE_TRANSACTION, data, reply, 0);
424
425        DatabaseUtils.readExceptionFromParcel(reply);
426        String out = reply.readString();
427
428        data.recycle();
429        reply.recycle();
430
431        return out;
432    }
433
434    public Uri insert(Uri url, ContentValues values) throws RemoteException
435    {
436        Parcel data = Parcel.obtain();
437        Parcel reply = Parcel.obtain();
438
439        data.writeInterfaceToken(IContentProvider.descriptor);
440
441        url.writeToParcel(data, 0);
442        values.writeToParcel(data, 0);
443
444        mRemote.transact(IContentProvider.INSERT_TRANSACTION, data, reply, 0);
445
446        DatabaseUtils.readExceptionFromParcel(reply);
447        Uri out = Uri.CREATOR.createFromParcel(reply);
448
449        data.recycle();
450        reply.recycle();
451
452        return out;
453    }
454
455    public int bulkInsert(Uri url, ContentValues[] values) throws RemoteException {
456        Parcel data = Parcel.obtain();
457        Parcel reply = Parcel.obtain();
458
459        data.writeInterfaceToken(IContentProvider.descriptor);
460
461        url.writeToParcel(data, 0);
462        data.writeTypedArray(values, 0);
463
464        mRemote.transact(IContentProvider.BULK_INSERT_TRANSACTION, data, reply, 0);
465
466        DatabaseUtils.readExceptionFromParcel(reply);
467        int count = reply.readInt();
468
469        data.recycle();
470        reply.recycle();
471
472        return count;
473    }
474
475    public Uri[] bulkInsertEntities(Uri uri, Entity[] entities) throws RemoteException {
476        Parcel data = Parcel.obtain();
477        Parcel reply = Parcel.obtain();
478
479        data.writeInterfaceToken(IContentProvider.descriptor);
480        uri.writeToParcel(data, 0);
481        data.writeString(entities[0].getClass().getName());
482        data.writeInt(entities.length);
483        for (Entity entity : entities) {
484            data.writeParcelable(entity, 0);
485        }
486
487        mRemote.transact(IContentProvider.BULK_INSERT_ENTITIES_TRANSACTION, data, reply, 0);
488
489        DatabaseUtils.readExceptionFromParcel(reply);
490        Uri[] results = new Uri[entities.length];
491        reply.readTypedArray(results, Uri.CREATOR);
492
493        data.recycle();
494        reply.recycle();
495
496        return results;
497    }
498
499    public int[] bulkUpdateEntities(Uri uri, Entity[] entities) throws RemoteException {
500        Parcel data = Parcel.obtain();
501        Parcel reply = Parcel.obtain();
502
503        data.writeInterfaceToken(IContentProvider.descriptor);
504        uri.writeToParcel(data, 0);
505        data.writeString(entities[0].getClass().getName());
506        data.writeInt(entities.length);
507        for (Entity entity : entities) {
508            data.writeParcelable(entity, 0);
509        }
510
511        mRemote.transact(IContentProvider.BULK_UPDATE_ENTITIES_TRANSACTION, data, reply, 0);
512
513        DatabaseUtils.readExceptionFromParcel(reply);
514        int[] results = new int[entities.length];
515        reply.readIntArray(results);
516
517        data.recycle();
518        reply.recycle();
519
520        return results;
521    }
522
523    public int delete(Uri url, String selection, String[] selectionArgs)
524            throws RemoteException {
525        Parcel data = Parcel.obtain();
526        Parcel reply = Parcel.obtain();
527
528        data.writeInterfaceToken(IContentProvider.descriptor);
529
530        url.writeToParcel(data, 0);
531        data.writeString(selection);
532        data.writeStringArray(selectionArgs);
533
534        mRemote.transact(IContentProvider.DELETE_TRANSACTION, data, reply, 0);
535
536        DatabaseUtils.readExceptionFromParcel(reply);
537        int count = reply.readInt();
538
539        data.recycle();
540        reply.recycle();
541
542        return count;
543    }
544
545    public int update(Uri url, ContentValues values, String selection,
546            String[] selectionArgs) throws RemoteException {
547        Parcel data = Parcel.obtain();
548        Parcel reply = Parcel.obtain();
549
550        data.writeInterfaceToken(IContentProvider.descriptor);
551
552        url.writeToParcel(data, 0);
553        values.writeToParcel(data, 0);
554        data.writeString(selection);
555        data.writeStringArray(selectionArgs);
556
557        mRemote.transact(IContentProvider.UPDATE_TRANSACTION, data, reply, 0);
558
559        DatabaseUtils.readExceptionFromParcel(reply);
560        int count = reply.readInt();
561
562        data.recycle();
563        reply.recycle();
564
565        return count;
566    }
567
568    public ParcelFileDescriptor openFile(Uri url, String mode)
569            throws RemoteException, FileNotFoundException {
570        Parcel data = Parcel.obtain();
571        Parcel reply = Parcel.obtain();
572
573        data.writeInterfaceToken(IContentProvider.descriptor);
574
575        url.writeToParcel(data, 0);
576        data.writeString(mode);
577
578        mRemote.transact(IContentProvider.OPEN_FILE_TRANSACTION, data, reply, 0);
579
580        DatabaseUtils.readExceptionWithFileNotFoundExceptionFromParcel(reply);
581        int has = reply.readInt();
582        ParcelFileDescriptor fd = has != 0 ? reply.readFileDescriptor() : null;
583
584        data.recycle();
585        reply.recycle();
586
587        return fd;
588    }
589
590    public AssetFileDescriptor openAssetFile(Uri url, String mode)
591            throws RemoteException, FileNotFoundException {
592        Parcel data = Parcel.obtain();
593        Parcel reply = Parcel.obtain();
594
595        data.writeInterfaceToken(IContentProvider.descriptor);
596
597        url.writeToParcel(data, 0);
598        data.writeString(mode);
599
600        mRemote.transact(IContentProvider.OPEN_ASSET_FILE_TRANSACTION, data, reply, 0);
601
602        DatabaseUtils.readExceptionWithFileNotFoundExceptionFromParcel(reply);
603        int has = reply.readInt();
604        AssetFileDescriptor fd = has != 0
605                ? AssetFileDescriptor.CREATOR.createFromParcel(reply) : null;
606
607        data.recycle();
608        reply.recycle();
609
610        return fd;
611    }
612
613    private IBinder mRemote;
614}
615
616