ContentProviderNative.java revision 77709755b74bcc852cd511ff833c2827c0f0e1aa
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 reset() throws RemoteException {
285            mEntityIterator.reset();
286        }
287
288        public void close() throws RemoteException {
289            mEntityIterator.close();
290        }
291    }
292
293    public IBinder asBinder()
294    {
295        return this;
296    }
297}
298
299
300final class ContentProviderProxy implements IContentProvider
301{
302    public ContentProviderProxy(IBinder remote)
303    {
304        mRemote = remote;
305    }
306
307    public IBinder asBinder()
308    {
309        return mRemote;
310    }
311
312    public IBulkCursor bulkQuery(Uri url, String[] projection,
313            String selection, String[] selectionArgs, String sortOrder, IContentObserver observer,
314            CursorWindow window) throws RemoteException {
315        Parcel data = Parcel.obtain();
316        Parcel reply = Parcel.obtain();
317
318        data.writeInterfaceToken(IContentProvider.descriptor);
319
320        url.writeToParcel(data, 0);
321        int length = 0;
322        if (projection != null) {
323            length = projection.length;
324        }
325        data.writeInt(length);
326        for (int i = 0; i < length; i++) {
327            data.writeString(projection[i]);
328        }
329        data.writeString(selection);
330        if (selectionArgs != null) {
331            length = selectionArgs.length;
332        } else {
333            length = 0;
334        }
335        data.writeInt(length);
336        for (int i = 0; i < length; i++) {
337            data.writeString(selectionArgs[i]);
338        }
339        data.writeString(sortOrder);
340        data.writeStrongBinder(observer.asBinder());
341        window.writeToParcel(data, 0);
342
343        mRemote.transact(IContentProvider.QUERY_TRANSACTION, data, reply, 0);
344
345        DatabaseUtils.readExceptionFromParcel(reply);
346
347        IBulkCursor bulkCursor = null;
348        IBinder bulkCursorBinder = reply.readStrongBinder();
349        if (bulkCursorBinder != null) {
350            bulkCursor = BulkCursorNative.asInterface(bulkCursorBinder);
351        }
352
353        data.recycle();
354        reply.recycle();
355
356        return bulkCursor;
357    }
358
359    public Cursor query(Uri url, String[] projection, String selection,
360            String[] selectionArgs, String sortOrder) throws RemoteException {
361        //TODO make a pool of windows so we can reuse memory dealers
362        CursorWindow window = new CursorWindow(false /* window will be used remotely */);
363        BulkCursorToCursorAdaptor adaptor = new BulkCursorToCursorAdaptor();
364        IBulkCursor bulkCursor = bulkQuery(url, projection, selection, selectionArgs, sortOrder,
365                adaptor.getObserver(), window);
366
367        if (bulkCursor == null) {
368            return null;
369        }
370        adaptor.set(bulkCursor);
371        return adaptor;
372    }
373
374    public EntityIterator queryEntities(Uri url, String selection, String[] selectionArgs,
375            String sortOrder)
376            throws RemoteException {
377        Parcel data = Parcel.obtain();
378        Parcel reply = Parcel.obtain();
379
380        data.writeInterfaceToken(IContentProvider.descriptor);
381
382        url.writeToParcel(data, 0);
383        data.writeString(selection);
384        data.writeStringArray(selectionArgs);
385        data.writeString(sortOrder);
386
387        mRemote.transact(IContentProvider.QUERY_ENTITIES_TRANSACTION, data, reply, 0);
388
389        DatabaseUtils.readExceptionFromParcel(reply);
390
391        IBinder entityIteratorBinder = reply.readStrongBinder();
392
393        data.recycle();
394        reply.recycle();
395
396        return new RemoteEntityIterator(IEntityIterator.Stub.asInterface(entityIteratorBinder));
397    }
398
399    static class RemoteEntityIterator implements EntityIterator {
400        private final IEntityIterator mEntityIterator;
401        RemoteEntityIterator(IEntityIterator entityIterator) {
402            mEntityIterator = entityIterator;
403        }
404
405        public boolean hasNext() throws RemoteException {
406            return mEntityIterator.hasNext();
407        }
408
409        public Entity next() throws RemoteException {
410            return mEntityIterator.next();
411        }
412
413        public void reset() throws RemoteException {
414            mEntityIterator.reset();
415        }
416
417        public void close() {
418            try {
419                mEntityIterator.close();
420            } catch (RemoteException e) {
421                // doesn't matter
422            }
423        }
424    }
425
426    public String getType(Uri url) throws RemoteException
427    {
428        Parcel data = Parcel.obtain();
429        Parcel reply = Parcel.obtain();
430
431        data.writeInterfaceToken(IContentProvider.descriptor);
432
433        url.writeToParcel(data, 0);
434
435        mRemote.transact(IContentProvider.GET_TYPE_TRANSACTION, data, reply, 0);
436
437        DatabaseUtils.readExceptionFromParcel(reply);
438        String out = reply.readString();
439
440        data.recycle();
441        reply.recycle();
442
443        return out;
444    }
445
446    public Uri insert(Uri url, ContentValues values) throws RemoteException
447    {
448        Parcel data = Parcel.obtain();
449        Parcel reply = Parcel.obtain();
450
451        data.writeInterfaceToken(IContentProvider.descriptor);
452
453        url.writeToParcel(data, 0);
454        values.writeToParcel(data, 0);
455
456        mRemote.transact(IContentProvider.INSERT_TRANSACTION, data, reply, 0);
457
458        DatabaseUtils.readExceptionFromParcel(reply);
459        Uri out = Uri.CREATOR.createFromParcel(reply);
460
461        data.recycle();
462        reply.recycle();
463
464        return out;
465    }
466
467    public int bulkInsert(Uri url, ContentValues[] values) throws RemoteException {
468        Parcel data = Parcel.obtain();
469        Parcel reply = Parcel.obtain();
470
471        data.writeInterfaceToken(IContentProvider.descriptor);
472
473        url.writeToParcel(data, 0);
474        data.writeTypedArray(values, 0);
475
476        mRemote.transact(IContentProvider.BULK_INSERT_TRANSACTION, data, reply, 0);
477
478        DatabaseUtils.readExceptionFromParcel(reply);
479        int count = reply.readInt();
480
481        data.recycle();
482        reply.recycle();
483
484        return count;
485    }
486
487    public ContentProviderResult[] applyBatch(ArrayList<ContentProviderOperation> operations)
488            throws RemoteException, OperationApplicationException {
489        Parcel data = Parcel.obtain();
490        Parcel reply = Parcel.obtain();
491
492        data.writeInterfaceToken(IContentProvider.descriptor);
493        data.writeInt(operations.size());
494        for (ContentProviderOperation operation : operations) {
495            operation.writeToParcel(data, 0);
496        }
497        mRemote.transact(IContentProvider.APPLY_BATCH_TRANSACTION, data, reply, 0);
498
499        DatabaseUtils.readExceptionWithOperationApplicationExceptionFromParcel(reply);
500        final ContentProviderResult[] results =
501                reply.createTypedArray(ContentProviderResult.CREATOR);
502
503        data.recycle();
504        reply.recycle();
505
506        return results;
507    }
508
509    public Uri insertEntity(Uri uri, Entity entity) throws RemoteException {
510        Parcel data = Parcel.obtain();
511        Parcel reply = Parcel.obtain();
512
513        try {
514            data.writeInterfaceToken(IContentProvider.descriptor);
515            uri.writeToParcel(data, 0);
516            data.writeParcelable(entity, 0);
517
518            mRemote.transact(IContentProvider.INSERT_ENTITIES_TRANSACTION, data, reply, 0);
519
520            DatabaseUtils.readExceptionFromParcel(reply);
521            return Uri.CREATOR.createFromParcel(reply);
522        } finally {
523            data.recycle();
524            reply.recycle();
525        }
526    }
527
528    public int updateEntity(Uri uri, Entity entity) throws RemoteException {
529        Parcel data = Parcel.obtain();
530        Parcel reply = Parcel.obtain();
531
532        try {
533            data.writeInterfaceToken(IContentProvider.descriptor);
534            uri.writeToParcel(data, 0);
535            data.writeParcelable(entity, 0);
536
537            mRemote.transact(IContentProvider.UPDATE_ENTITIES_TRANSACTION, data, reply, 0);
538
539            DatabaseUtils.readExceptionFromParcel(reply);
540            return reply.readInt();
541        } finally {
542            data.recycle();
543            reply.recycle();
544        }
545    }
546
547    public int delete(Uri url, String selection, String[] selectionArgs)
548            throws RemoteException {
549        Parcel data = Parcel.obtain();
550        Parcel reply = Parcel.obtain();
551
552        data.writeInterfaceToken(IContentProvider.descriptor);
553
554        url.writeToParcel(data, 0);
555        data.writeString(selection);
556        data.writeStringArray(selectionArgs);
557
558        mRemote.transact(IContentProvider.DELETE_TRANSACTION, data, reply, 0);
559
560        DatabaseUtils.readExceptionFromParcel(reply);
561        int count = reply.readInt();
562
563        data.recycle();
564        reply.recycle();
565
566        return count;
567    }
568
569    public int update(Uri url, ContentValues values, String selection,
570            String[] selectionArgs) throws RemoteException {
571        Parcel data = Parcel.obtain();
572        Parcel reply = Parcel.obtain();
573
574        data.writeInterfaceToken(IContentProvider.descriptor);
575
576        url.writeToParcel(data, 0);
577        values.writeToParcel(data, 0);
578        data.writeString(selection);
579        data.writeStringArray(selectionArgs);
580
581        mRemote.transact(IContentProvider.UPDATE_TRANSACTION, data, reply, 0);
582
583        DatabaseUtils.readExceptionFromParcel(reply);
584        int count = reply.readInt();
585
586        data.recycle();
587        reply.recycle();
588
589        return count;
590    }
591
592    public ParcelFileDescriptor openFile(Uri url, String mode)
593            throws RemoteException, FileNotFoundException {
594        Parcel data = Parcel.obtain();
595        Parcel reply = Parcel.obtain();
596
597        data.writeInterfaceToken(IContentProvider.descriptor);
598
599        url.writeToParcel(data, 0);
600        data.writeString(mode);
601
602        mRemote.transact(IContentProvider.OPEN_FILE_TRANSACTION, data, reply, 0);
603
604        DatabaseUtils.readExceptionWithFileNotFoundExceptionFromParcel(reply);
605        int has = reply.readInt();
606        ParcelFileDescriptor fd = has != 0 ? reply.readFileDescriptor() : null;
607
608        data.recycle();
609        reply.recycle();
610
611        return fd;
612    }
613
614    public AssetFileDescriptor openAssetFile(Uri url, String mode)
615            throws RemoteException, FileNotFoundException {
616        Parcel data = Parcel.obtain();
617        Parcel reply = Parcel.obtain();
618
619        data.writeInterfaceToken(IContentProvider.descriptor);
620
621        url.writeToParcel(data, 0);
622        data.writeString(mode);
623
624        mRemote.transact(IContentProvider.OPEN_ASSET_FILE_TRANSACTION, data, reply, 0);
625
626        DatabaseUtils.readExceptionWithFileNotFoundExceptionFromParcel(reply);
627        int has = reply.readInt();
628        AssetFileDescriptor fd = has != 0
629                ? AssetFileDescriptor.CREATOR.createFromParcel(reply) : null;
630
631        data.recycle();
632        reply.recycle();
633
634        return fd;
635    }
636
637    private IBinder mRemote;
638}
639
640