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