M7350/base/core/java/android/content/ContentProviderNative.java
2024-09-09 08:52:07 +00:00

573 lines
19 KiB
Java

/*
* 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.BulkCursorNative;
import android.database.BulkCursorToCursorAdaptor;
import android.database.Cursor;
import android.database.CursorWindow;
import android.database.DatabaseUtils;
import android.database.IBulkCursor;
import android.database.IContentObserver;
import android.net.Uri;
import android.os.Binder;
import android.os.Bundle;
import android.os.RemoteException;
import android.os.IBinder;
import android.os.Parcel;
import android.os.ParcelFileDescriptor;
import android.os.Parcelable;
import java.io.FileNotFoundException;
import java.util.ArrayList;
/**
* {@hide}
*/
abstract public class ContentProviderNative extends Binder implements IContentProvider {
private static final String TAG = "ContentProvider";
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);
}
@Override
public boolean onTransact(int code, Parcel data, Parcel reply, int flags)
throws RemoteException {
try {
switch (code) {
case QUERY_TRANSACTION:
{
data.enforceInterface(IContentProvider.descriptor);
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());
CursorWindow window = CursorWindow.CREATOR.createFromParcel(data);
// Flag for whether caller wants the number of
// rows in the cursor and the position of the
// "_id" column index (or -1 if non-existent)
// Only to be returned if binder != null.
boolean wantsCursorMetadata = data.readInt() != 0;
IBulkCursor bulkCursor = bulkQuery(url, projection, selection,
selectionArgs, sortOrder, observer, window);
reply.writeNoException();
if (bulkCursor != null) {
reply.writeStrongBinder(bulkCursor.asBinder());
if (wantsCursorMetadata) {
reply.writeInt(bulkCursor.count());
reply.writeInt(BulkCursorToCursorAdaptor.findRowIdColumnIndex(
bulkCursor.getColumnNames()));
}
} else {
reply.writeStrongBinder(null);
}
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);
Uri url = Uri.CREATOR.createFromParcel(data);
ContentValues values = ContentValues.CREATOR.createFromParcel(data);
Uri out = insert(url, values);
reply.writeNoException();
Uri.writeToParcel(reply, out);
return true;
}
case BULK_INSERT_TRANSACTION:
{
data.enforceInterface(IContentProvider.descriptor);
Uri url = Uri.CREATOR.createFromParcel(data);
ContentValues[] values = data.createTypedArray(ContentValues.CREATOR);
int count = bulkInsert(url, values);
reply.writeNoException();
reply.writeInt(count);
return true;
}
case APPLY_BATCH_TRANSACTION:
{
data.enforceInterface(IContentProvider.descriptor);
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(operations);
reply.writeNoException();
reply.writeTypedArray(results, 0);
return true;
}
case DELETE_TRANSACTION:
{
data.enforceInterface(IContentProvider.descriptor);
Uri url = Uri.CREATOR.createFromParcel(data);
String selection = data.readString();
String[] selectionArgs = data.readStringArray();
int count = delete(url, selection, selectionArgs);
reply.writeNoException();
reply.writeInt(count);
return true;
}
case UPDATE_TRANSACTION:
{
data.enforceInterface(IContentProvider.descriptor);
Uri url = Uri.CREATOR.createFromParcel(data);
ContentValues values = ContentValues.CREATOR.createFromParcel(data);
String selection = data.readString();
String[] selectionArgs = data.readStringArray();
int count = update(url, values, selection, selectionArgs);
reply.writeNoException();
reply.writeInt(count);
return true;
}
case OPEN_FILE_TRANSACTION:
{
data.enforceInterface(IContentProvider.descriptor);
Uri url = Uri.CREATOR.createFromParcel(data);
String mode = data.readString();
ParcelFileDescriptor fd;
fd = openFile(url, mode);
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);
Uri url = Uri.CREATOR.createFromParcel(data);
String mode = data.readString();
AssetFileDescriptor fd;
fd = openAssetFile(url, mode);
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 method = data.readString();
String stringArg = data.readString();
Bundle args = data.readBundle();
Bundle responseBundle = call(method, stringArg, args);
reply.writeNoException();
reply.writeBundle(responseBundle);
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;
}
// Like bulkQuery() but sets up provided 'adaptor' if not null.
private IBulkCursor bulkQueryInternal(
Uri url, String[] projection,
String selection, String[] selectionArgs, String sortOrder,
IContentObserver observer, CursorWindow window,
BulkCursorToCursorAdaptor adaptor) throws RemoteException {
Parcel data = Parcel.obtain();
Parcel reply = Parcel.obtain();
data.writeInterfaceToken(IContentProvider.descriptor);
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(observer.asBinder());
window.writeToParcel(data, 0);
// Flag for whether or not we want the number of rows in the
// cursor and the position of the "_id" column index (or -1 if
// non-existent). Only to be returned if binder != null.
final boolean wantsCursorMetadata = (adaptor != null);
data.writeInt(wantsCursorMetadata ? 1 : 0);
mRemote.transact(IContentProvider.QUERY_TRANSACTION, data, reply, 0);
DatabaseUtils.readExceptionFromParcel(reply);
IBulkCursor bulkCursor = null;
IBinder bulkCursorBinder = reply.readStrongBinder();
if (bulkCursorBinder != null) {
bulkCursor = BulkCursorNative.asInterface(bulkCursorBinder);
if (wantsCursorMetadata) {
int rowCount = reply.readInt();
int idColumnPosition = reply.readInt();
if (bulkCursor != null) {
adaptor.set(bulkCursor, rowCount, idColumnPosition);
}
}
}
data.recycle();
reply.recycle();
return bulkCursor;
}
public IBulkCursor bulkQuery(Uri url, String[] projection,
String selection, String[] selectionArgs, String sortOrder, IContentObserver observer,
CursorWindow window) throws RemoteException {
return bulkQueryInternal(
url, projection, selection, selectionArgs, sortOrder,
observer, window,
null /* BulkCursorToCursorAdaptor */);
}
public Cursor query(Uri url, String[] projection, String selection,
String[] selectionArgs, String sortOrder) throws RemoteException {
//TODO make a pool of windows so we can reuse memory dealers
CursorWindow window = new CursorWindow(false /* window will be used remotely */);
BulkCursorToCursorAdaptor adaptor = new BulkCursorToCursorAdaptor();
IBulkCursor bulkCursor = bulkQueryInternal(
url, projection, selection, selectionArgs, sortOrder,
adaptor.getObserver(), window,
adaptor);
if (bulkCursor == null) {
return null;
}
return adaptor;
}
public String getType(Uri url) throws RemoteException
{
Parcel data = Parcel.obtain();
Parcel reply = Parcel.obtain();
data.writeInterfaceToken(IContentProvider.descriptor);
url.writeToParcel(data, 0);
mRemote.transact(IContentProvider.GET_TYPE_TRANSACTION, data, reply, 0);
DatabaseUtils.readExceptionFromParcel(reply);
String out = reply.readString();
data.recycle();
reply.recycle();
return out;
}
public Uri insert(Uri url, ContentValues values) throws RemoteException
{
Parcel data = Parcel.obtain();
Parcel reply = Parcel.obtain();
data.writeInterfaceToken(IContentProvider.descriptor);
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);
data.recycle();
reply.recycle();
return out;
}
public int bulkInsert(Uri url, ContentValues[] values) throws RemoteException {
Parcel data = Parcel.obtain();
Parcel reply = Parcel.obtain();
data.writeInterfaceToken(IContentProvider.descriptor);
url.writeToParcel(data, 0);
data.writeTypedArray(values, 0);
mRemote.transact(IContentProvider.BULK_INSERT_TRANSACTION, data, reply, 0);
DatabaseUtils.readExceptionFromParcel(reply);
int count = reply.readInt();
data.recycle();
reply.recycle();
return count;
}
public ContentProviderResult[] applyBatch(ArrayList<ContentProviderOperation> operations)
throws RemoteException, OperationApplicationException {
Parcel data = Parcel.obtain();
Parcel reply = Parcel.obtain();
data.writeInterfaceToken(IContentProvider.descriptor);
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);
data.recycle();
reply.recycle();
return results;
}
public int delete(Uri url, String selection, String[] selectionArgs)
throws RemoteException {
Parcel data = Parcel.obtain();
Parcel reply = Parcel.obtain();
data.writeInterfaceToken(IContentProvider.descriptor);
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();
data.recycle();
reply.recycle();
return count;
}
public int update(Uri url, ContentValues values, String selection,
String[] selectionArgs) throws RemoteException {
Parcel data = Parcel.obtain();
Parcel reply = Parcel.obtain();
data.writeInterfaceToken(IContentProvider.descriptor);
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();
data.recycle();
reply.recycle();
return count;
}
public ParcelFileDescriptor openFile(Uri url, String mode)
throws RemoteException, FileNotFoundException {
Parcel data = Parcel.obtain();
Parcel reply = Parcel.obtain();
data.writeInterfaceToken(IContentProvider.descriptor);
url.writeToParcel(data, 0);
data.writeString(mode);
mRemote.transact(IContentProvider.OPEN_FILE_TRANSACTION, data, reply, 0);
DatabaseUtils.readExceptionWithFileNotFoundExceptionFromParcel(reply);
int has = reply.readInt();
ParcelFileDescriptor fd = has != 0 ? reply.readFileDescriptor() : null;
data.recycle();
reply.recycle();
return fd;
}
public AssetFileDescriptor openAssetFile(Uri url, String mode)
throws RemoteException, FileNotFoundException {
Parcel data = Parcel.obtain();
Parcel reply = Parcel.obtain();
data.writeInterfaceToken(IContentProvider.descriptor);
url.writeToParcel(data, 0);
data.writeString(mode);
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;
data.recycle();
reply.recycle();
return fd;
}
public Bundle call(String method, String request, Bundle args)
throws RemoteException {
Parcel data = Parcel.obtain();
Parcel reply = Parcel.obtain();
data.writeInterfaceToken(IContentProvider.descriptor);
data.writeString(method);
data.writeString(request);
data.writeBundle(args);
mRemote.transact(IContentProvider.CALL_TRANSACTION, data, reply, 0);
DatabaseUtils.readExceptionFromParcel(reply);
Bundle bundle = reply.readBundle();
data.recycle();
reply.recycle();
return bundle;
}
private IBinder mRemote;
}