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