1/*
2 * Copyright (C) 2006 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package android.content;
18
19import android.annotation.Nullable;
20import android.content.res.AssetFileDescriptor;
21import android.database.BulkCursorDescriptor;
22import android.database.BulkCursorToCursorAdaptor;
23import android.database.Cursor;
24import android.database.CursorToBulkCursorAdaptor;
25import android.database.DatabaseUtils;
26import android.database.IContentObserver;
27import android.net.Uri;
28import android.os.Binder;
29import android.os.Bundle;
30import android.os.IBinder;
31import android.os.ICancellationSignal;
32import android.os.Parcel;
33import android.os.ParcelFileDescriptor;
34import android.os.Parcelable;
35import android.os.RemoteException;
36
37import java.io.FileNotFoundException;
38import java.util.ArrayList;
39
40/**
41 * {@hide}
42 */
43abstract public class ContentProviderNative extends Binder implements IContentProvider {
44    public ContentProviderNative()
45    {
46        attachInterface(this, descriptor);
47    }
48
49    /**
50     * Cast a Binder object into a content resolver interface, generating
51     * a proxy if needed.
52     */
53    static public IContentProvider asInterface(IBinder obj)
54    {
55        if (obj == null) {
56            return null;
57        }
58        IContentProvider in =
59            (IContentProvider)obj.queryLocalInterface(descriptor);
60        if (in != null) {
61            return in;
62        }
63
64        return new ContentProviderProxy(obj);
65    }
66
67    /**
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     */
72    public abstract String getProviderName();
73
74    @Override
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
371    public IBinder asBinder()
372    {
373        return this;
374    }
375}
376
377
378final class ContentProviderProxy implements IContentProvider
379{
380    public ContentProviderProxy(IBinder remote)
381    {
382        mRemote = remote;
383    }
384
385    @Override
386    public IBinder asBinder()
387    {
388        return mRemote;
389    }
390
391    @Override
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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