ContentProviderNative.java revision 1877d0158b529663b8315482e7346a7bcaa96166
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.Bundle;
30import android.os.RemoteException;
31import android.os.IBinder;
32import android.os.Parcel;
33import android.os.ParcelFileDescriptor;
34import android.os.Parcelable;
35
36import java.io.FileNotFoundException;
37import java.util.ArrayList;
38
39/**
40 * {@hide}
41 */
42abstract public class ContentProviderNative extends Binder implements IContentProvider {
43    private static final String TAG = "ContentProvider";
44
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    @Override
69    public boolean onTransact(int code, Parcel data, Parcel reply, int flags)
70            throws RemoteException {
71        try {
72            switch (code) {
73                case QUERY_TRANSACTION:
74                {
75                    data.enforceInterface(IContentProvider.descriptor);
76                    Uri url = Uri.CREATOR.createFromParcel(data);
77                    int num = data.readInt();
78                    String[] projection = null;
79                    if (num > 0) {
80                        projection = new String[num];
81                        for (int i = 0; i < num; i++) {
82                            projection[i] = data.readString();
83                        }
84                    }
85                    String selection = data.readString();
86                    num = data.readInt();
87                    String[] selectionArgs = null;
88                    if (num > 0) {
89                        selectionArgs = new String[num];
90                        for (int i = 0; i < num; i++) {
91                            selectionArgs[i] = data.readString();
92                        }
93                    }
94                    String sortOrder = data.readString();
95                    IContentObserver observer = IContentObserver.Stub.
96                        asInterface(data.readStrongBinder());
97                    CursorWindow window = CursorWindow.CREATOR.createFromParcel(data);
98
99                    IBulkCursor bulkCursor = bulkQuery(url, projection, selection,
100                            selectionArgs, sortOrder, observer, window);
101                    reply.writeNoException();
102                    if (bulkCursor != null) {
103                        reply.writeStrongBinder(bulkCursor.asBinder());
104                    } else {
105                        reply.writeStrongBinder(null);
106                    }
107                    return true;
108                }
109
110                case GET_TYPE_TRANSACTION:
111                {
112                    data.enforceInterface(IContentProvider.descriptor);
113                    Uri url = Uri.CREATOR.createFromParcel(data);
114                    String type = getType(url);
115                    reply.writeNoException();
116                    reply.writeString(type);
117
118                    return true;
119                }
120
121                case INSERT_TRANSACTION:
122                {
123                    data.enforceInterface(IContentProvider.descriptor);
124                    Uri url = Uri.CREATOR.createFromParcel(data);
125                    ContentValues values = ContentValues.CREATOR.createFromParcel(data);
126
127                    Uri out = insert(url, values);
128                    reply.writeNoException();
129                    Uri.writeToParcel(reply, out);
130                    return true;
131                }
132
133                case BULK_INSERT_TRANSACTION:
134                {
135                    data.enforceInterface(IContentProvider.descriptor);
136                    Uri url = Uri.CREATOR.createFromParcel(data);
137                    ContentValues[] values = data.createTypedArray(ContentValues.CREATOR);
138
139                    int count = bulkInsert(url, values);
140                    reply.writeNoException();
141                    reply.writeInt(count);
142                    return true;
143                }
144
145                case APPLY_BATCH_TRANSACTION:
146                {
147                    data.enforceInterface(IContentProvider.descriptor);
148                    final int numOperations = data.readInt();
149                    final ArrayList<ContentProviderOperation> operations =
150                            new ArrayList<ContentProviderOperation>(numOperations);
151                    for (int i = 0; i < numOperations; i++) {
152                        operations.add(i, ContentProviderOperation.CREATOR.createFromParcel(data));
153                    }
154                    final ContentProviderResult[] results = applyBatch(operations);
155                    reply.writeNoException();
156                    reply.writeTypedArray(results, 0);
157                    return true;
158                }
159
160                case DELETE_TRANSACTION:
161                {
162                    data.enforceInterface(IContentProvider.descriptor);
163                    Uri url = Uri.CREATOR.createFromParcel(data);
164                    String selection = data.readString();
165                    String[] selectionArgs = data.readStringArray();
166
167                    int count = delete(url, selection, selectionArgs);
168
169                    reply.writeNoException();
170                    reply.writeInt(count);
171                    return true;
172                }
173
174                case UPDATE_TRANSACTION:
175                {
176                    data.enforceInterface(IContentProvider.descriptor);
177                    Uri url = Uri.CREATOR.createFromParcel(data);
178                    ContentValues values = ContentValues.CREATOR.createFromParcel(data);
179                    String selection = data.readString();
180                    String[] selectionArgs = data.readStringArray();
181
182                    int count = update(url, values, selection, selectionArgs);
183
184                    reply.writeNoException();
185                    reply.writeInt(count);
186                    return true;
187                }
188
189                case OPEN_FILE_TRANSACTION:
190                {
191                    data.enforceInterface(IContentProvider.descriptor);
192                    Uri url = Uri.CREATOR.createFromParcel(data);
193                    String mode = data.readString();
194
195                    ParcelFileDescriptor fd;
196                    fd = openFile(url, mode);
197                    reply.writeNoException();
198                    if (fd != null) {
199                        reply.writeInt(1);
200                        fd.writeToParcel(reply,
201                                Parcelable.PARCELABLE_WRITE_RETURN_VALUE);
202                    } else {
203                        reply.writeInt(0);
204                    }
205                    return true;
206                }
207
208                case OPEN_ASSET_FILE_TRANSACTION:
209                {
210                    data.enforceInterface(IContentProvider.descriptor);
211                    Uri url = Uri.CREATOR.createFromParcel(data);
212                    String mode = data.readString();
213
214                    AssetFileDescriptor fd;
215                    fd = openAssetFile(url, mode);
216                    reply.writeNoException();
217                    if (fd != null) {
218                        reply.writeInt(1);
219                        fd.writeToParcel(reply,
220                                Parcelable.PARCELABLE_WRITE_RETURN_VALUE);
221                    } else {
222                        reply.writeInt(0);
223                    }
224                    return true;
225                }
226
227                case CALL_TRANSACTION:
228                {
229                    data.enforceInterface(IContentProvider.descriptor);
230
231                    String method = data.readString();
232                    String stringArg = data.readString();
233                    Bundle args = data.readBundle();
234
235                    Bundle responseBundle = call(method, stringArg, args);
236
237                    reply.writeNoException();
238                    reply.writeBundle(responseBundle);
239                    return true;
240                }
241            }
242        } catch (Exception e) {
243            DatabaseUtils.writeExceptionToParcel(reply, e);
244            return true;
245        }
246
247        return super.onTransact(code, data, reply, flags);
248    }
249
250    public IBinder asBinder()
251    {
252        return this;
253    }
254}
255
256
257final class ContentProviderProxy implements IContentProvider
258{
259    public ContentProviderProxy(IBinder remote)
260    {
261        mRemote = remote;
262    }
263
264    public IBinder asBinder()
265    {
266        return mRemote;
267    }
268
269    public IBulkCursor bulkQuery(Uri url, String[] projection,
270            String selection, String[] selectionArgs, String sortOrder, IContentObserver observer,
271            CursorWindow window) throws RemoteException {
272        Parcel data = Parcel.obtain();
273        Parcel reply = Parcel.obtain();
274
275        data.writeInterfaceToken(IContentProvider.descriptor);
276
277        url.writeToParcel(data, 0);
278        int length = 0;
279        if (projection != null) {
280            length = projection.length;
281        }
282        data.writeInt(length);
283        for (int i = 0; i < length; i++) {
284            data.writeString(projection[i]);
285        }
286        data.writeString(selection);
287        if (selectionArgs != null) {
288            length = selectionArgs.length;
289        } else {
290            length = 0;
291        }
292        data.writeInt(length);
293        for (int i = 0; i < length; i++) {
294            data.writeString(selectionArgs[i]);
295        }
296        data.writeString(sortOrder);
297        data.writeStrongBinder(observer.asBinder());
298        window.writeToParcel(data, 0);
299
300        mRemote.transact(IContentProvider.QUERY_TRANSACTION, data, reply, 0);
301
302        DatabaseUtils.readExceptionFromParcel(reply);
303
304        IBulkCursor bulkCursor = null;
305        IBinder bulkCursorBinder = reply.readStrongBinder();
306        if (bulkCursorBinder != null) {
307            bulkCursor = BulkCursorNative.asInterface(bulkCursorBinder);
308        }
309
310        data.recycle();
311        reply.recycle();
312
313        return bulkCursor;
314    }
315
316    public Cursor query(Uri url, String[] projection, String selection,
317            String[] selectionArgs, String sortOrder) throws RemoteException {
318        //TODO make a pool of windows so we can reuse memory dealers
319        CursorWindow window = new CursorWindow(false /* window will be used remotely */);
320        BulkCursorToCursorAdaptor adaptor = new BulkCursorToCursorAdaptor();
321        IBulkCursor bulkCursor = bulkQuery(url, projection, selection, selectionArgs, sortOrder,
322                adaptor.getObserver(), window);
323
324        if (bulkCursor == null) {
325            return null;
326        }
327        adaptor.set(bulkCursor);
328        return adaptor;
329    }
330
331    public String getType(Uri url) throws RemoteException
332    {
333        Parcel data = Parcel.obtain();
334        Parcel reply = Parcel.obtain();
335
336        data.writeInterfaceToken(IContentProvider.descriptor);
337
338        url.writeToParcel(data, 0);
339
340        mRemote.transact(IContentProvider.GET_TYPE_TRANSACTION, data, reply, 0);
341
342        DatabaseUtils.readExceptionFromParcel(reply);
343        String out = reply.readString();
344
345        data.recycle();
346        reply.recycle();
347
348        return out;
349    }
350
351    public Uri insert(Uri url, ContentValues values) throws RemoteException
352    {
353        Parcel data = Parcel.obtain();
354        Parcel reply = Parcel.obtain();
355
356        data.writeInterfaceToken(IContentProvider.descriptor);
357
358        url.writeToParcel(data, 0);
359        values.writeToParcel(data, 0);
360
361        mRemote.transact(IContentProvider.INSERT_TRANSACTION, data, reply, 0);
362
363        DatabaseUtils.readExceptionFromParcel(reply);
364        Uri out = Uri.CREATOR.createFromParcel(reply);
365
366        data.recycle();
367        reply.recycle();
368
369        return out;
370    }
371
372    public int bulkInsert(Uri url, ContentValues[] values) throws RemoteException {
373        Parcel data = Parcel.obtain();
374        Parcel reply = Parcel.obtain();
375
376        data.writeInterfaceToken(IContentProvider.descriptor);
377
378        url.writeToParcel(data, 0);
379        data.writeTypedArray(values, 0);
380
381        mRemote.transact(IContentProvider.BULK_INSERT_TRANSACTION, data, reply, 0);
382
383        DatabaseUtils.readExceptionFromParcel(reply);
384        int count = reply.readInt();
385
386        data.recycle();
387        reply.recycle();
388
389        return count;
390    }
391
392    public ContentProviderResult[] applyBatch(ArrayList<ContentProviderOperation> operations)
393            throws RemoteException, OperationApplicationException {
394        Parcel data = Parcel.obtain();
395        Parcel reply = Parcel.obtain();
396
397        data.writeInterfaceToken(IContentProvider.descriptor);
398        data.writeInt(operations.size());
399        for (ContentProviderOperation operation : operations) {
400            operation.writeToParcel(data, 0);
401        }
402        mRemote.transact(IContentProvider.APPLY_BATCH_TRANSACTION, data, reply, 0);
403
404        DatabaseUtils.readExceptionWithOperationApplicationExceptionFromParcel(reply);
405        final ContentProviderResult[] results =
406                reply.createTypedArray(ContentProviderResult.CREATOR);
407
408        data.recycle();
409        reply.recycle();
410
411        return results;
412    }
413
414    public int delete(Uri url, String selection, String[] selectionArgs)
415            throws RemoteException {
416        Parcel data = Parcel.obtain();
417        Parcel reply = Parcel.obtain();
418
419        data.writeInterfaceToken(IContentProvider.descriptor);
420
421        url.writeToParcel(data, 0);
422        data.writeString(selection);
423        data.writeStringArray(selectionArgs);
424
425        mRemote.transact(IContentProvider.DELETE_TRANSACTION, data, reply, 0);
426
427        DatabaseUtils.readExceptionFromParcel(reply);
428        int count = reply.readInt();
429
430        data.recycle();
431        reply.recycle();
432
433        return count;
434    }
435
436    public int update(Uri url, ContentValues values, String selection,
437            String[] selectionArgs) throws RemoteException {
438        Parcel data = Parcel.obtain();
439        Parcel reply = Parcel.obtain();
440
441        data.writeInterfaceToken(IContentProvider.descriptor);
442
443        url.writeToParcel(data, 0);
444        values.writeToParcel(data, 0);
445        data.writeString(selection);
446        data.writeStringArray(selectionArgs);
447
448        mRemote.transact(IContentProvider.UPDATE_TRANSACTION, data, reply, 0);
449
450        DatabaseUtils.readExceptionFromParcel(reply);
451        int count = reply.readInt();
452
453        data.recycle();
454        reply.recycle();
455
456        return count;
457    }
458
459    public ParcelFileDescriptor openFile(Uri url, String mode)
460            throws RemoteException, FileNotFoundException {
461        Parcel data = Parcel.obtain();
462        Parcel reply = Parcel.obtain();
463
464        data.writeInterfaceToken(IContentProvider.descriptor);
465
466        url.writeToParcel(data, 0);
467        data.writeString(mode);
468
469        mRemote.transact(IContentProvider.OPEN_FILE_TRANSACTION, data, reply, 0);
470
471        DatabaseUtils.readExceptionWithFileNotFoundExceptionFromParcel(reply);
472        int has = reply.readInt();
473        ParcelFileDescriptor fd = has != 0 ? reply.readFileDescriptor() : null;
474
475        data.recycle();
476        reply.recycle();
477
478        return fd;
479    }
480
481    public AssetFileDescriptor openAssetFile(Uri url, String mode)
482            throws RemoteException, FileNotFoundException {
483        Parcel data = Parcel.obtain();
484        Parcel reply = Parcel.obtain();
485
486        data.writeInterfaceToken(IContentProvider.descriptor);
487
488        url.writeToParcel(data, 0);
489        data.writeString(mode);
490
491        mRemote.transact(IContentProvider.OPEN_ASSET_FILE_TRANSACTION, data, reply, 0);
492
493        DatabaseUtils.readExceptionWithFileNotFoundExceptionFromParcel(reply);
494        int has = reply.readInt();
495        AssetFileDescriptor fd = has != 0
496                ? AssetFileDescriptor.CREATOR.createFromParcel(reply) : null;
497
498        data.recycle();
499        reply.recycle();
500
501        return fd;
502    }
503
504    public Bundle call(String method, String request, Bundle args)
505            throws RemoteException {
506        Parcel data = Parcel.obtain();
507        Parcel reply = Parcel.obtain();
508
509        data.writeInterfaceToken(IContentProvider.descriptor);
510
511        data.writeString(method);
512        data.writeString(request);
513        data.writeBundle(args);
514
515        mRemote.transact(IContentProvider.CALL_TRANSACTION, data, reply, 0);
516
517        DatabaseUtils.readExceptionFromParcel(reply);
518        return reply.readBundle();
519    }
520
521    private IBinder mRemote;
522}
523