/*
* Copyright (C) 2006 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package android.content;
import android.content.res.AssetFileDescriptor;
import android.database.BulkCursorDescriptor;
import android.database.BulkCursorToCursorAdaptor;
import android.database.Cursor;
import android.database.CursorToBulkCursorAdaptor;
import android.database.DatabaseUtils;
import android.database.IContentObserver;
import android.net.Uri;
import android.os.Binder;
import android.os.Bundle;
import android.os.IBinder;
import android.os.ICancellationSignal;
import android.os.Parcel;
import android.os.ParcelFileDescriptor;
import android.os.Parcelable;
import android.os.RemoteException;
import java.io.FileNotFoundException;
import java.util.ArrayList;
/**
* {@hide}
*/
abstract public class ContentProviderNative extends Binder implements IContentProvider {
public ContentProviderNative()
{
attachInterface(this, descriptor);
}
/**
* Cast a Binder object into a content resolver interface, generating
* a proxy if needed.
*/
static public IContentProvider asInterface(IBinder obj)
{
if (obj == null) {
return null;
}
IContentProvider in =
(IContentProvider)obj.queryLocalInterface(descriptor);
if (in != null) {
return in;
}
return new ContentProviderProxy(obj);
}
/**
* Gets the name of the content provider.
* Should probably be part of the {@link IContentProvider} interface.
* @return The content provider name.
*/
public abstract String getProviderName();
@Override
public boolean onTransact(int code, Parcel data, Parcel reply, int flags)
throws RemoteException {
try {
switch (code) {
case QUERY_TRANSACTION:
{
data.enforceInterface(IContentProvider.descriptor);
String callingPkg = data.readString();
Uri url = Uri.CREATOR.createFromParcel(data);
// String[] projection
int num = data.readInt();
String[] projection = null;
if (num > 0) {
projection = new String[num];
for (int i = 0; i < num; i++) {
projection[i] = data.readString();
}
}
// String selection, String[] selectionArgs...
String selection = data.readString();
num = data.readInt();
String[] selectionArgs = null;
if (num > 0) {
selectionArgs = new String[num];
for (int i = 0; i < num; i++) {
selectionArgs[i] = data.readString();
}
}
String sortOrder = data.readString();
IContentObserver observer = IContentObserver.Stub.asInterface(
data.readStrongBinder());
ICancellationSignal cancellationSignal = ICancellationSignal.Stub.asInterface(
data.readStrongBinder());
Cursor cursor = query(callingPkg, url, projection, selection, selectionArgs,
sortOrder, cancellationSignal);
if (cursor != null) {
CursorToBulkCursorAdaptor adaptor = null;
try {
adaptor = new CursorToBulkCursorAdaptor(cursor, observer,
getProviderName());
cursor = null;
BulkCursorDescriptor d = adaptor.getBulkCursorDescriptor();
adaptor = null;
reply.writeNoException();
reply.writeInt(1);
d.writeToParcel(reply, Parcelable.PARCELABLE_WRITE_RETURN_VALUE);
} finally {
// Close cursor if an exception was thrown while constructing the adaptor.
if (adaptor != null) {
adaptor.close();
}
if (cursor != null) {
cursor.close();
}
}
} else {
reply.writeNoException();
reply.writeInt(0);
}
return true;
}
case GET_TYPE_TRANSACTION:
{
data.enforceInterface(IContentProvider.descriptor);
Uri url = Uri.CREATOR.createFromParcel(data);
String type = getType(url);
reply.writeNoException();
reply.writeString(type);
return true;
}
case INSERT_TRANSACTION:
{
data.enforceInterface(IContentProvider.descriptor);
String callingPkg = data.readString();
Uri url = Uri.CREATOR.createFromParcel(data);
ContentValues values = ContentValues.CREATOR.createFromParcel(data);
Uri out = insert(callingPkg, url, values);
reply.writeNoException();
Uri.writeToParcel(reply, out);
return true;
}
case BULK_INSERT_TRANSACTION:
{
data.enforceInterface(IContentProvider.descriptor);
String callingPkg = data.readString();
Uri url = Uri.CREATOR.createFromParcel(data);
ContentValues[] values = data.createTypedArray(ContentValues.CREATOR);
int count = bulkInsert(callingPkg, url, values);
reply.writeNoException();
reply.writeInt(count);
return true;
}
case APPLY_BATCH_TRANSACTION:
{
data.enforceInterface(IContentProvider.descriptor);
String callingPkg = data.readString();
final int numOperations = data.readInt();
final ArrayList<ContentProviderOperation> operations =
new ArrayList<ContentProviderOperation>(numOperations);
for (int i = 0; i < numOperations; i++) {
operations.add(i, ContentProviderOperation.CREATOR.createFromParcel(data));
}
final ContentProviderResult[] results = applyBatch(callingPkg, operations);
reply.writeNoException();
reply.writeTypedArray(results, 0);
return true;
}
case DELETE_TRANSACTION:
{
data.enforceInterface(IContentProvider.descriptor);
String callingPkg = data.readString();
Uri url = Uri.CREATOR.createFromParcel(data);
String selection = data.readString();
String[] selectionArgs = data.readStringArray();
int count = delete(callingPkg, url, selection, selectionArgs);
reply.writeNoException();
reply.writeInt(count);
return true;
}
case UPDATE_TRANSACTION:
{
data.enforceInterface(IContentProvider.descriptor);
String callingPkg = data.readString();
Uri url = Uri.CREATOR.createFromParcel(data);
ContentValues values = ContentValues.CREATOR.createFromParcel(data);
String selection = data.readString();
String[] selectionArgs = data.readStringArray();
int count = update(callingPkg, url, values, selection, selectionArgs);
reply.writeNoException();
reply.writeInt(count);
return true;
}
case OPEN_FILE_TRANSACTION:
{
data.enforceInterface(IContentProvider.descriptor);
String callingPkg = data.readString();
Uri url = Uri.CREATOR.createFromParcel(data);
String mode = data.readString();
ICancellationSignal signal = ICancellationSignal.Stub.asInterface(
data.readStrongBinder());
IBinder callerToken = data.readStrongBinder();
ParcelFileDescriptor fd;
fd = openFile(callingPkg, url, mode, signal, callerToken);
reply.writeNoException();
if (fd != null) {
reply.writeInt(1);
fd.writeToParcel(reply,
Parcelable.PARCELABLE_WRITE_RETURN_VALUE);
} else {
reply.writeInt(0);
}
return true;
}
case OPEN_ASSET_FILE_TRANSACTION:
{
data.enforceInterface(IContentProvider.descriptor);
String callingPkg = data.readString();
Uri url = Uri.CREATOR.createFromParcel(data);
String mode = data.readString();
ICancellationSignal signal = ICancellationSignal.Stub.asInterface(
data.readStrongBinder());
AssetFileDescriptor fd;
fd = openAssetFile(callingPkg, url, mode, signal);
reply.writeNoException();
if (fd != null) {
reply.writeInt(1);
fd.writeToParcel(reply,
Parcelable.PARCELABLE_WRITE_RETURN_VALUE);
} else {
reply.writeInt(0);
}
return true;
}
case CALL_TRANSACTION:
{
data.enforceInterface(IContentProvider.descriptor);
String callingPkg = data.readString();
String method = data.readString();
String stringArg = data.readString();
Bundle args = data.readBundle();
Bundle responseBundle = call(callingPkg, method, stringArg, args);
reply.writeNoException();
reply.writeBundle(responseBundle);
return true;
}
case GET_STREAM_TYPES_TRANSACTION:
{
data.enforceInterface(IContentProvider.descriptor);
Uri url = Uri.CREATOR.createFromParcel(data);
String mimeTypeFilter = data.readString();
String[] types = getStreamTypes(url, mimeTypeFilter);
reply.writeNoException();
reply.writeStringArray(types);
return true;
}
case OPEN_TYPED_ASSET_FILE_TRANSACTION:
{
data.enforceInterface(IContentProvider.descriptor);
String callingPkg = data.readString();
Uri url = Uri.CREATOR.createFromParcel(data);
String mimeType = data.readString();
Bundle opts = data.readBundle();
ICancellationSignal signal = ICancellationSignal.Stub.asInterface(
data.readStrongBinder());
AssetFileDescriptor fd;
fd = openTypedAssetFile(callingPkg, url, mimeType, opts, signal);
reply.writeNoException();
if (fd != null) {
reply.writeInt(1);
fd.writeToParcel(reply,
Parcelable.PARCELABLE_WRITE_RETURN_VALUE);
} else {
reply.writeInt(0);
}
return true;
}
case CREATE_CANCELATION_SIGNAL_TRANSACTION:
{
data.enforceInterface(IContentProvider.descriptor);
ICancellationSignal cancellationSignal = createCancellationSignal();
reply.writeNoException();
reply.writeStrongBinder(cancellationSignal.asBinder());
return true;
}
case CANONICALIZE_TRANSACTION:
{
data.enforceInterface(IContentProvider.descriptor);
String callingPkg = data.readString();
Uri url = Uri.CREATOR.createFromParcel(data);
Uri out = canonicalize(callingPkg, url);
reply.writeNoException();
Uri.writeToParcel(reply, out);
return true;
}
case UNCANONICALIZE_TRANSACTION:
{
data.enforceInterface(IContentProvider.descriptor);
String callingPkg = data.readString();
Uri url = Uri.CREATOR.createFromParcel(data);
Uri out = uncanonicalize(callingPkg, url);
reply.writeNoException();
Uri.writeToParcel(reply, out);
return true;
}
}
} catch (Exception e) {
DatabaseUtils.writeExceptionToParcel(reply, e);
return true;
}
return super.onTransact(code, data, reply, flags);
}
public IBinder asBinder()
{
return this;
}
}
final class ContentProviderProxy implements IContentProvider
{
public ContentProviderProxy(IBinder remote)
{
mRemote = remote;
}
public IBinder asBinder()
{
return mRemote;
}
public Cursor query(String callingPkg, Uri url, String[] projection, String selection,
String[] selectionArgs, String sortOrder, ICancellationSignal cancellationSignal)
throws RemoteException {
BulkCursorToCursorAdaptor adaptor = new BulkCursorToCursorAdaptor();
Parcel data = Parcel.obtain();
Parcel reply = Parcel.obtain();
try {
data.writeInterfaceToken(IContentProvider.descriptor);
data.writeString(callingPkg);
url.writeToParcel(data, 0);
int length = 0;
if (projection != null) {
length = projection.length;
}
data.writeInt(length);
for (int i = 0; i < length; i++) {
data.writeString(projection[i]);
}
data.writeString(selection);
if (selectionArgs != null) {
length = selectionArgs.length;
} else {
length = 0;
}
data.writeInt(length);
for (int i = 0; i < length; i++) {
data.writeString(selectionArgs[i]);
}
data.writeString(sortOrder);
data.writeStrongBinder(adaptor.getObserver().asBinder());
data.writeStrongBinder(cancellationSignal != null ? cancellationSignal.asBinder() : null);
mRemote.transact(IContentProvider.QUERY_TRANSACTION, data, reply, 0);
DatabaseUtils.readExceptionFromParcel(reply);
if (reply.readInt() != 0) {
BulkCursorDescriptor d = BulkCursorDescriptor.CREATOR.createFromParcel(reply);
adaptor.initialize(d);
} else {
adaptor.close();
adaptor = null;
}
return adaptor;
} catch (RemoteException ex) {
adaptor.close();
throw ex;
} catch (RuntimeException ex) {
adaptor.close();
throw ex;
} finally {
data.recycle();
reply.recycle();
}
}
public String getType(Uri url) throws RemoteException
{
Parcel data = Parcel.obtain();
Parcel reply = Parcel.obtain();
try {
data.writeInterfaceToken(IContentProvider.descriptor);
url.writeToParcel(data, 0);
mRemote.transact(IContentProvider.GET_TYPE_TRANSACTION, data, reply, 0);
DatabaseUtils.readExceptionFromParcel(reply);
String out = reply.readString();
return out;
} finally {
data.recycle();
reply.recycle();
}
}
public Uri insert(String callingPkg, Uri url, ContentValues values) throws RemoteException
{
Parcel data = Parcel.obtain();
Parcel reply = Parcel.obtain();
try {
data.writeInterfaceToken(IContentProvider.descriptor);
data.writeString(callingPkg);
url.writeToParcel(data, 0);
values.writeToParcel(data, 0);
mRemote.transact(IContentProvider.INSERT_TRANSACTION, data, reply, 0);
DatabaseUtils.readExceptionFromParcel(reply);
Uri out = Uri.CREATOR.createFromParcel(reply);
return out;
} finally {
data.recycle();
reply.recycle();
}
}
public int bulkInsert(String callingPkg, Uri url, ContentValues[] values) throws RemoteException {
Parcel data = Parcel.obtain();
Parcel reply = Parcel.obtain();
try {
data.writeInterfaceToken(IContentProvider.descriptor);
data.writeString(callingPkg);
url.writeToParcel(data, 0);
data.writeTypedArray(values, 0);
mRemote.transact(IContentProvider.BULK_INSERT_TRANSACTION, data, reply, 0);
DatabaseUtils.readExceptionFromParcel(reply);
int count = reply.readInt();
return count;
} finally {
data.recycle();
reply.recycle();
}
}
public ContentProviderResult[] applyBatch(String callingPkg,
ArrayList<ContentProviderOperation> operations)
throws RemoteException, OperationApplicationException {
Parcel data = Parcel.obtain();
Parcel reply = Parcel.obtain();
try {
data.writeInterfaceToken(IContentProvider.descriptor);
data.writeString(callingPkg);
data.writeInt(operations.size());
for (ContentProviderOperation operation : operations) {
operation.writeToParcel(data, 0);
}
mRemote.transact(IContentProvider.APPLY_BATCH_TRANSACTION, data, reply, 0);
DatabaseUtils.readExceptionWithOperationApplicationExceptionFromParcel(reply);
final ContentProviderResult[] results =
reply.createTypedArray(ContentProviderResult.CREATOR);
return results;
} finally {
data.recycle();
reply.recycle();
}
}
public int delete(String callingPkg, Uri url, String selection, String[] selectionArgs)
throws RemoteException {
Parcel data = Parcel.obtain();
Parcel reply = Parcel.obtain();
try {
data.writeInterfaceToken(IContentProvider.descriptor);
data.writeString(callingPkg);
url.writeToParcel(data, 0);
data.writeString(selection);
data.writeStringArray(selectionArgs);
mRemote.transact(IContentProvider.DELETE_TRANSACTION, data, reply, 0);
DatabaseUtils.readExceptionFromParcel(reply);
int count = reply.readInt();
return count;
} finally {
data.recycle();
reply.recycle();
}
}
public int update(String callingPkg, Uri url, ContentValues values, String selection,
String[] selectionArgs) throws RemoteException {
Parcel data = Parcel.obtain();
Parcel reply = Parcel.obtain();
try {
data.writeInterfaceToken(IContentProvider.descriptor);
data.writeString(callingPkg);
url.writeToParcel(data, 0);
values.writeToParcel(data, 0);
data.writeString(selection);
data.writeStringArray(selectionArgs);
mRemote.transact(IContentProvider.UPDATE_TRANSACTION, data, reply, 0);
DatabaseUtils.readExceptionFromParcel(reply);
int count = reply.readInt();
return count;
} finally {
data.recycle();
reply.recycle();
}
}
@Override
public ParcelFileDescriptor openFile(
String callingPkg, Uri url, String mode, ICancellationSignal signal, IBinder token)
throws RemoteException, FileNotFoundException {
Parcel data = Parcel.obtain();
Parcel reply = Parcel.obtain();
try {
data.writeInterfaceToken(IContentProvider.descriptor);
data.writeString(callingPkg);
url.writeToParcel(data, 0);
data.writeString(mode);
data.writeStrongBinder(signal != null ? signal.asBinder() : null);
data.writeStrongBinder(token);
mRemote.transact(IContentProvider.OPEN_FILE_TRANSACTION, data, reply, 0);
DatabaseUtils.readExceptionWithFileNotFoundExceptionFromParcel(reply);
int has = reply.readInt();
ParcelFileDescriptor fd = has != 0 ? ParcelFileDescriptor.CREATOR
.createFromParcel(reply) : null;
return fd;
} finally {
data.recycle();
reply.recycle();
}
}
@Override
public AssetFileDescriptor openAssetFile(
String callingPkg, Uri url, String mode, ICancellationSignal signal)
throws RemoteException, FileNotFoundException {
Parcel data = Parcel.obtain();
Parcel reply = Parcel.obtain();
try {
data.writeInterfaceToken(IContentProvider.descriptor);
data.writeString(callingPkg);
url.writeToParcel(data, 0);
data.writeString(mode);
data.writeStrongBinder(signal != null ? signal.asBinder() : null);
mRemote.transact(IContentProvider.OPEN_ASSET_FILE_TRANSACTION, data, reply, 0);
DatabaseUtils.readExceptionWithFileNotFoundExceptionFromParcel(reply);
int has = reply.readInt();
AssetFileDescriptor fd = has != 0
? AssetFileDescriptor.CREATOR.createFromParcel(reply) : null;
return fd;
} finally {
data.recycle();
reply.recycle();
}
}
public Bundle call(String callingPkg, String method, String request, Bundle args)
throws RemoteException {
Parcel data = Parcel.obtain();
Parcel reply = Parcel.obtain();
try {
data.writeInterfaceToken(IContentProvider.descriptor);
data.writeString(callingPkg);
data.writeString(method);
data.writeString(request);
data.writeBundle(args);
mRemote.transact(IContentProvider.CALL_TRANSACTION, data, reply, 0);
DatabaseUtils.readExceptionFromParcel(reply);
Bundle bundle = reply.readBundle();
return bundle;
} finally {
data.recycle();
reply.recycle();
}
}
public String[] getStreamTypes(Uri url, String mimeTypeFilter) throws RemoteException
{
Parcel data = Parcel.obtain();
Parcel reply = Parcel.obtain();
try {
data.writeInterfaceToken(IContentProvider.descriptor);
url.writeToParcel(data, 0);
data.writeString(mimeTypeFilter);
mRemote.transact(IContentProvider.GET_STREAM_TYPES_TRANSACTION, data, reply, 0);
DatabaseUtils.readExceptionFromParcel(reply);
String[] out = reply.createStringArray();
return out;
} finally {
data.recycle();
reply.recycle();
}
}
@Override
public AssetFileDescriptor openTypedAssetFile(String callingPkg, Uri url, String mimeType,
Bundle opts, ICancellationSignal signal) throws RemoteException, FileNotFoundException {
Parcel data = Parcel.obtain();
Parcel reply = Parcel.obtain();
try {
data.writeInterfaceToken(IContentProvider.descriptor);
data.writeString(callingPkg);
url.writeToParcel(data, 0);
data.writeString(mimeType);
data.writeBundle(opts);
data.writeStrongBinder(signal != null ? signal.asBinder() : null);
mRemote.transact(IContentProvider.OPEN_TYPED_ASSET_FILE_TRANSACTION, data, reply, 0);
DatabaseUtils.readExceptionWithFileNotFoundExceptionFromParcel(reply);
int has = reply.readInt();
AssetFileDescriptor fd = has != 0
? AssetFileDescriptor.CREATOR.createFromParcel(reply) : null;
return fd;
} finally {
data.recycle();
reply.recycle();
}
}
public ICancellationSignal createCancellationSignal() throws RemoteException {
Parcel data = Parcel.obtain();
Parcel reply = Parcel.obtain();
try {
data.writeInterfaceToken(IContentProvider.descriptor);
mRemote.transact(IContentProvider.CREATE_CANCELATION_SIGNAL_TRANSACTION,
data, reply, 0);
DatabaseUtils.readExceptionFromParcel(reply);
ICancellationSignal cancellationSignal = ICancellationSignal.Stub.asInterface(
reply.readStrongBinder());
return cancellationSignal;
} finally {
data.recycle();
reply.recycle();
}
}
public Uri canonicalize(String callingPkg, Uri url) throws RemoteException
{
Parcel data = Parcel.obtain();
Parcel reply = Parcel.obtain();
try {
data.writeInterfaceToken(IContentProvider.descriptor);
data.writeString(callingPkg);
url.writeToParcel(data, 0);
mRemote.transact(IContentProvider.CANONICALIZE_TRANSACTION, data, reply, 0);
DatabaseUtils.readExceptionFromParcel(reply);
Uri out = Uri.CREATOR.createFromParcel(reply);
return out;
} finally {
data.recycle();
reply.recycle();
}
}
public Uri uncanonicalize(String callingPkg, Uri url) throws RemoteException {
Parcel data = Parcel.obtain();
Parcel reply = Parcel.obtain();
try {
data.writeInterfaceToken(IContentProvider.descriptor);
data.writeString(callingPkg);
url.writeToParcel(data, 0);
mRemote.transact(IContentProvider.UNCANONICALIZE_TRANSACTION, data, reply, 0);
DatabaseUtils.readExceptionFromParcel(reply);
Uri out = Uri.CREATOR.createFromParcel(reply);
return out;
} finally {
data.recycle();
reply.recycle();
}
}
private IBinder mRemote;
}