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