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