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