ContentProviderNative.java revision 54b6cfa9a9e5b861a9930af873580d6dc20f773c
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.database.BulkCursorNative;
20import android.database.BulkCursorToCursorAdaptor;
21import android.database.Cursor;
22import android.database.CursorWindow;
23import android.database.DatabaseUtils;
24import android.database.IBulkCursor;
25import android.database.IContentObserver;
26import android.net.Uri;
27import android.os.Binder;
28import android.os.RemoteException;
29import android.os.IBinder;
30import android.os.Parcel;
31import android.os.ParcelFileDescriptor;
32import android.os.Parcelable;
33
34import java.io.FileNotFoundException;
35
36/**
37 * {@hide}
38 */
39abstract public class ContentProviderNative extends Binder implements IContentProvider {
40    private static final String TAG = "ContentProvider";
41
42    public ContentProviderNative()
43    {
44        attachInterface(this, descriptor);
45    }
46
47    /**
48     * Cast a Binder object into a content resolver interface, generating
49     * a proxy if needed.
50     */
51    static public IContentProvider asInterface(IBinder obj)
52    {
53        if (obj == null) {
54            return null;
55        }
56        IContentProvider in =
57            (IContentProvider)obj.queryLocalInterface(descriptor);
58        if (in != null) {
59            return in;
60        }
61
62        return new ContentProviderProxy(obj);
63    }
64
65    @Override
66    public boolean onTransact(int code, Parcel data, Parcel reply, int flags)
67            throws RemoteException {
68        try {
69            switch (code) {
70                case QUERY_TRANSACTION:
71                {
72                    data.enforceInterface(IContentProvider.descriptor);
73                    Uri url = Uri.CREATOR.createFromParcel(data);
74                    int num = data.readInt();
75                    String[] projection = null;
76                    if (num > 0) {
77                        projection = new String[num];
78                        for (int i = 0; i < num; i++) {
79                            projection[i] = data.readString();
80                        }
81                    }
82                    String selection = data.readString();
83                    num = data.readInt();
84                    String[] selectionArgs = null;
85                    if (num > 0) {
86                        selectionArgs = new String[num];
87                        for (int i = 0; i < num; i++) {
88                            selectionArgs[i] = data.readString();
89                        }
90                    }
91                    String sortOrder = data.readString();
92                    IContentObserver observer = IContentObserver.Stub.
93                        asInterface(data.readStrongBinder());
94                    CursorWindow window = CursorWindow.CREATOR.createFromParcel(data);
95
96                    IBulkCursor bulkCursor = bulkQuery(url, projection, selection,
97                            selectionArgs, sortOrder, observer, window);
98                    reply.writeNoException();
99                    if (bulkCursor != null) {
100                        reply.writeStrongBinder(bulkCursor.asBinder());
101                    } else {
102                        reply.writeStrongBinder(null);
103                    }
104                    return true;
105                }
106
107                case GET_TYPE_TRANSACTION:
108                {
109                    data.enforceInterface(IContentProvider.descriptor);
110                    Uri url = Uri.CREATOR.createFromParcel(data);
111                    String type = getType(url);
112                    reply.writeNoException();
113                    reply.writeString(type);
114
115                    return true;
116                }
117
118                case INSERT_TRANSACTION:
119                {
120                    data.enforceInterface(IContentProvider.descriptor);
121                    Uri url = Uri.CREATOR.createFromParcel(data);
122                    ContentValues values = ContentValues.CREATOR.createFromParcel(data);
123
124                    Uri out = insert(url, values);
125                    reply.writeNoException();
126                    Uri.writeToParcel(reply, out);
127                    return true;
128                }
129
130                case BULK_INSERT_TRANSACTION:
131                {
132                    data.enforceInterface(IContentProvider.descriptor);
133                    Uri url = Uri.CREATOR.createFromParcel(data);
134                    ContentValues[] values = data.createTypedArray(ContentValues.CREATOR);
135
136                    int count = bulkInsert(url, values);
137                    reply.writeNoException();
138                    reply.writeInt(count);
139                    return true;
140                }
141
142                case DELETE_TRANSACTION:
143                {
144                    data.enforceInterface(IContentProvider.descriptor);
145                    Uri url = Uri.CREATOR.createFromParcel(data);
146                    String selection = data.readString();
147                    String[] selectionArgs = data.readStringArray();
148
149                    int count = delete(url, selection, selectionArgs);
150
151                    reply.writeNoException();
152                    reply.writeInt(count);
153                    return true;
154                }
155
156                case UPDATE_TRANSACTION:
157                {
158                    data.enforceInterface(IContentProvider.descriptor);
159                    Uri url = Uri.CREATOR.createFromParcel(data);
160                    ContentValues values = ContentValues.CREATOR.createFromParcel(data);
161                    String selection = data.readString();
162                    String[] selectionArgs = data.readStringArray();
163
164                    int count = update(url, values, selection, selectionArgs);
165
166                    reply.writeNoException();
167                    reply.writeInt(count);
168                    return true;
169                }
170
171                case OPEN_FILE_TRANSACTION:
172                {
173                    data.enforceInterface(IContentProvider.descriptor);
174                    Uri url = Uri.CREATOR.createFromParcel(data);
175                    String mode = data.readString();
176
177                    ParcelFileDescriptor fd;
178                    fd = openFile(url, mode);
179                    reply.writeNoException();
180                    if (fd != null) {
181                        reply.writeInt(1);
182                        fd.writeToParcel(reply,
183                                Parcelable.PARCELABLE_WRITE_RETURN_VALUE);
184                    } else {
185                        reply.writeInt(0);
186                    }
187                    return true;
188                }
189
190                case GET_SYNC_ADAPTER_TRANSACTION:
191                {
192                    data.enforceInterface(IContentProvider.descriptor);
193                    ISyncAdapter sa = getSyncAdapter();
194                    reply.writeNoException();
195                    reply.writeStrongBinder(sa != null ? sa.asBinder() : null);
196                    return true;
197                }
198            }
199        } catch (Exception e) {
200            DatabaseUtils.writeExceptionToParcel(reply, e);
201            return true;
202        }
203
204        return super.onTransact(code, data, reply, flags);
205    }
206
207    public IBinder asBinder()
208    {
209        return this;
210    }
211}
212
213
214final class ContentProviderProxy implements IContentProvider
215{
216    public ContentProviderProxy(IBinder remote)
217    {
218        mRemote = remote;
219    }
220
221    public IBinder asBinder()
222    {
223        return mRemote;
224    }
225
226    public IBulkCursor bulkQuery(Uri url, String[] projection,
227            String selection, String[] selectionArgs, String sortOrder, IContentObserver observer,
228            CursorWindow window) throws RemoteException {
229        Parcel data = Parcel.obtain();
230        Parcel reply = Parcel.obtain();
231
232        data.writeInterfaceToken(IContentProvider.descriptor);
233
234        url.writeToParcel(data, 0);
235        int length = 0;
236        if (projection != null) {
237            length = projection.length;
238        }
239        data.writeInt(length);
240        for (int i = 0; i < length; i++) {
241            data.writeString(projection[i]);
242        }
243        data.writeString(selection);
244        if (selectionArgs != null) {
245            length = selectionArgs.length;
246        } else {
247            length = 0;
248        }
249        data.writeInt(length);
250        for (int i = 0; i < length; i++) {
251            data.writeString(selectionArgs[i]);
252        }
253        data.writeString(sortOrder);
254        data.writeStrongBinder(observer.asBinder());
255        window.writeToParcel(data, 0);
256
257        mRemote.transact(IContentProvider.QUERY_TRANSACTION, data, reply, 0);
258
259        DatabaseUtils.readExceptionFromParcel(reply);
260
261        IBulkCursor bulkCursor = null;
262        IBinder bulkCursorBinder = reply.readStrongBinder();
263        if (bulkCursorBinder != null) {
264            bulkCursor = BulkCursorNative.asInterface(bulkCursorBinder);
265        }
266
267        data.recycle();
268        reply.recycle();
269
270        return bulkCursor;
271    }
272
273    public Cursor query(Uri url, String[] projection, String selection,
274            String[] selectionArgs, String sortOrder) throws RemoteException {
275        //TODO make a pool of windows so we can reuse memory dealers
276        CursorWindow window = new CursorWindow(false /* window will be used remotely */);
277        BulkCursorToCursorAdaptor adaptor = new BulkCursorToCursorAdaptor();
278        IBulkCursor bulkCursor = bulkQuery(url, projection, selection, selectionArgs, sortOrder,
279                adaptor.getObserver(), window);
280
281        if (bulkCursor == null) {
282            return null;
283        }
284        adaptor.set(bulkCursor);
285        return adaptor;
286    }
287
288    public String getType(Uri url) throws RemoteException
289    {
290        Parcel data = Parcel.obtain();
291        Parcel reply = Parcel.obtain();
292
293        data.writeInterfaceToken(IContentProvider.descriptor);
294
295        url.writeToParcel(data, 0);
296
297        mRemote.transact(IContentProvider.GET_TYPE_TRANSACTION, data, reply, 0);
298
299        DatabaseUtils.readExceptionFromParcel(reply);
300        String out = reply.readString();
301
302        data.recycle();
303        reply.recycle();
304
305        return out;
306    }
307
308    public Uri insert(Uri url, ContentValues values) throws RemoteException
309    {
310        Parcel data = Parcel.obtain();
311        Parcel reply = Parcel.obtain();
312
313        data.writeInterfaceToken(IContentProvider.descriptor);
314
315        url.writeToParcel(data, 0);
316        values.writeToParcel(data, 0);
317
318        mRemote.transact(IContentProvider.INSERT_TRANSACTION, data, reply, 0);
319
320        DatabaseUtils.readExceptionFromParcel(reply);
321        Uri out = Uri.CREATOR.createFromParcel(reply);
322
323        data.recycle();
324        reply.recycle();
325
326        return out;
327    }
328
329    public int bulkInsert(Uri url, ContentValues[] values) throws RemoteException {
330        Parcel data = Parcel.obtain();
331        Parcel reply = Parcel.obtain();
332
333        data.writeInterfaceToken(IContentProvider.descriptor);
334
335        url.writeToParcel(data, 0);
336        data.writeTypedArray(values, 0);
337
338        mRemote.transact(IContentProvider.BULK_INSERT_TRANSACTION, data, reply, 0);
339
340        DatabaseUtils.readExceptionFromParcel(reply);
341        int count = reply.readInt();
342
343        data.recycle();
344        reply.recycle();
345
346        return count;
347    }
348
349    public int delete(Uri url, String selection, String[] selectionArgs)
350            throws RemoteException {
351        Parcel data = Parcel.obtain();
352        Parcel reply = Parcel.obtain();
353
354        data.writeInterfaceToken(IContentProvider.descriptor);
355
356        url.writeToParcel(data, 0);
357        data.writeString(selection);
358        data.writeStringArray(selectionArgs);
359
360        mRemote.transact(IContentProvider.DELETE_TRANSACTION, data, reply, 0);
361
362        DatabaseUtils.readExceptionFromParcel(reply);
363        int count = reply.readInt();
364
365        data.recycle();
366        reply.recycle();
367
368        return count;
369    }
370
371    public int update(Uri url, ContentValues values, String selection,
372            String[] selectionArgs) 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        values.writeToParcel(data, 0);
380        data.writeString(selection);
381        data.writeStringArray(selectionArgs);
382
383        mRemote.transact(IContentProvider.UPDATE_TRANSACTION, data, reply, 0);
384
385        DatabaseUtils.readExceptionFromParcel(reply);
386        int count = reply.readInt();
387
388        data.recycle();
389        reply.recycle();
390
391        return count;
392    }
393
394    public ParcelFileDescriptor openFile(Uri url, String mode)
395            throws RemoteException, FileNotFoundException {
396        Parcel data = Parcel.obtain();
397        Parcel reply = Parcel.obtain();
398
399        data.writeInterfaceToken(IContentProvider.descriptor);
400
401        url.writeToParcel(data, 0);
402        data.writeString(mode);
403
404        mRemote.transact(IContentProvider.OPEN_FILE_TRANSACTION, data, reply, 0);
405
406        DatabaseUtils.readExceptionWithFileNotFoundExceptionFromParcel(reply);
407        int has = reply.readInt();
408        ParcelFileDescriptor fd = has != 0 ? reply.readFileDescriptor() : null;
409
410        data.recycle();
411        reply.recycle();
412
413        return fd;
414    }
415
416    public ISyncAdapter getSyncAdapter() throws RemoteException {
417        Parcel data = Parcel.obtain();
418        Parcel reply = Parcel.obtain();
419
420        data.writeInterfaceToken(IContentProvider.descriptor);
421
422        mRemote.transact(IContentProvider.GET_SYNC_ADAPTER_TRANSACTION, data, reply, 0);
423
424        DatabaseUtils.readExceptionFromParcel(reply);
425        ISyncAdapter syncAdapter = ISyncAdapter.Stub.asInterface(reply.readStrongBinder());
426
427        data.recycle();
428        reply.recycle();
429
430        return syncAdapter;
431    }
432
433    private IBinder mRemote;
434}
435
436