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