ContentProviderNative.java revision 1877d0158b529663b8315482e7346a7bcaa96166
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.content.res.AssetFileDescriptor; 20import android.database.BulkCursorNative; 21import android.database.BulkCursorToCursorAdaptor; 22import android.database.Cursor; 23import android.database.CursorWindow; 24import android.database.DatabaseUtils; 25import android.database.IBulkCursor; 26import android.database.IContentObserver; 27import android.net.Uri; 28import android.os.Binder; 29import android.os.Bundle; 30import android.os.RemoteException; 31import android.os.IBinder; 32import android.os.Parcel; 33import android.os.ParcelFileDescriptor; 34import android.os.Parcelable; 35 36import java.io.FileNotFoundException; 37import java.util.ArrayList; 38 39/** 40 * {@hide} 41 */ 42abstract public class ContentProviderNative extends Binder implements IContentProvider { 43 private static final String TAG = "ContentProvider"; 44 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 static public IContentProvider asInterface(IBinder obj) 55 { 56 if (obj == null) { 57 return null; 58 } 59 IContentProvider in = 60 (IContentProvider)obj.queryLocalInterface(descriptor); 61 if (in != null) { 62 return in; 63 } 64 65 return new ContentProviderProxy(obj); 66 } 67 68 @Override 69 public boolean onTransact(int code, Parcel data, Parcel reply, int flags) 70 throws RemoteException { 71 try { 72 switch (code) { 73 case QUERY_TRANSACTION: 74 { 75 data.enforceInterface(IContentProvider.descriptor); 76 Uri url = Uri.CREATOR.createFromParcel(data); 77 int num = data.readInt(); 78 String[] projection = null; 79 if (num > 0) { 80 projection = new String[num]; 81 for (int i = 0; i < num; i++) { 82 projection[i] = data.readString(); 83 } 84 } 85 String selection = data.readString(); 86 num = data.readInt(); 87 String[] selectionArgs = null; 88 if (num > 0) { 89 selectionArgs = new String[num]; 90 for (int i = 0; i < num; i++) { 91 selectionArgs[i] = data.readString(); 92 } 93 } 94 String sortOrder = data.readString(); 95 IContentObserver observer = IContentObserver.Stub. 96 asInterface(data.readStrongBinder()); 97 CursorWindow window = CursorWindow.CREATOR.createFromParcel(data); 98 99 IBulkCursor bulkCursor = bulkQuery(url, projection, selection, 100 selectionArgs, sortOrder, observer, window); 101 reply.writeNoException(); 102 if (bulkCursor != null) { 103 reply.writeStrongBinder(bulkCursor.asBinder()); 104 } else { 105 reply.writeStrongBinder(null); 106 } 107 return true; 108 } 109 110 case GET_TYPE_TRANSACTION: 111 { 112 data.enforceInterface(IContentProvider.descriptor); 113 Uri url = Uri.CREATOR.createFromParcel(data); 114 String type = getType(url); 115 reply.writeNoException(); 116 reply.writeString(type); 117 118 return true; 119 } 120 121 case INSERT_TRANSACTION: 122 { 123 data.enforceInterface(IContentProvider.descriptor); 124 Uri url = Uri.CREATOR.createFromParcel(data); 125 ContentValues values = ContentValues.CREATOR.createFromParcel(data); 126 127 Uri out = insert(url, values); 128 reply.writeNoException(); 129 Uri.writeToParcel(reply, out); 130 return true; 131 } 132 133 case BULK_INSERT_TRANSACTION: 134 { 135 data.enforceInterface(IContentProvider.descriptor); 136 Uri url = Uri.CREATOR.createFromParcel(data); 137 ContentValues[] values = data.createTypedArray(ContentValues.CREATOR); 138 139 int count = bulkInsert(url, values); 140 reply.writeNoException(); 141 reply.writeInt(count); 142 return true; 143 } 144 145 case APPLY_BATCH_TRANSACTION: 146 { 147 data.enforceInterface(IContentProvider.descriptor); 148 final int numOperations = data.readInt(); 149 final ArrayList<ContentProviderOperation> operations = 150 new ArrayList<ContentProviderOperation>(numOperations); 151 for (int i = 0; i < numOperations; i++) { 152 operations.add(i, ContentProviderOperation.CREATOR.createFromParcel(data)); 153 } 154 final ContentProviderResult[] results = applyBatch(operations); 155 reply.writeNoException(); 156 reply.writeTypedArray(results, 0); 157 return true; 158 } 159 160 case DELETE_TRANSACTION: 161 { 162 data.enforceInterface(IContentProvider.descriptor); 163 Uri url = Uri.CREATOR.createFromParcel(data); 164 String selection = data.readString(); 165 String[] selectionArgs = data.readStringArray(); 166 167 int count = delete(url, selection, selectionArgs); 168 169 reply.writeNoException(); 170 reply.writeInt(count); 171 return true; 172 } 173 174 case UPDATE_TRANSACTION: 175 { 176 data.enforceInterface(IContentProvider.descriptor); 177 Uri url = Uri.CREATOR.createFromParcel(data); 178 ContentValues values = ContentValues.CREATOR.createFromParcel(data); 179 String selection = data.readString(); 180 String[] selectionArgs = data.readStringArray(); 181 182 int count = update(url, values, selection, selectionArgs); 183 184 reply.writeNoException(); 185 reply.writeInt(count); 186 return true; 187 } 188 189 case OPEN_FILE_TRANSACTION: 190 { 191 data.enforceInterface(IContentProvider.descriptor); 192 Uri url = Uri.CREATOR.createFromParcel(data); 193 String mode = data.readString(); 194 195 ParcelFileDescriptor fd; 196 fd = openFile(url, mode); 197 reply.writeNoException(); 198 if (fd != null) { 199 reply.writeInt(1); 200 fd.writeToParcel(reply, 201 Parcelable.PARCELABLE_WRITE_RETURN_VALUE); 202 } else { 203 reply.writeInt(0); 204 } 205 return true; 206 } 207 208 case OPEN_ASSET_FILE_TRANSACTION: 209 { 210 data.enforceInterface(IContentProvider.descriptor); 211 Uri url = Uri.CREATOR.createFromParcel(data); 212 String mode = data.readString(); 213 214 AssetFileDescriptor fd; 215 fd = openAssetFile(url, mode); 216 reply.writeNoException(); 217 if (fd != null) { 218 reply.writeInt(1); 219 fd.writeToParcel(reply, 220 Parcelable.PARCELABLE_WRITE_RETURN_VALUE); 221 } else { 222 reply.writeInt(0); 223 } 224 return true; 225 } 226 227 case CALL_TRANSACTION: 228 { 229 data.enforceInterface(IContentProvider.descriptor); 230 231 String method = data.readString(); 232 String stringArg = data.readString(); 233 Bundle args = data.readBundle(); 234 235 Bundle responseBundle = call(method, stringArg, args); 236 237 reply.writeNoException(); 238 reply.writeBundle(responseBundle); 239 return true; 240 } 241 } 242 } catch (Exception e) { 243 DatabaseUtils.writeExceptionToParcel(reply, e); 244 return true; 245 } 246 247 return super.onTransact(code, data, reply, flags); 248 } 249 250 public IBinder asBinder() 251 { 252 return this; 253 } 254} 255 256 257final class ContentProviderProxy implements IContentProvider 258{ 259 public ContentProviderProxy(IBinder remote) 260 { 261 mRemote = remote; 262 } 263 264 public IBinder asBinder() 265 { 266 return mRemote; 267 } 268 269 public IBulkCursor bulkQuery(Uri url, String[] projection, 270 String selection, String[] selectionArgs, String sortOrder, IContentObserver observer, 271 CursorWindow window) throws RemoteException { 272 Parcel data = Parcel.obtain(); 273 Parcel reply = Parcel.obtain(); 274 275 data.writeInterfaceToken(IContentProvider.descriptor); 276 277 url.writeToParcel(data, 0); 278 int length = 0; 279 if (projection != null) { 280 length = projection.length; 281 } 282 data.writeInt(length); 283 for (int i = 0; i < length; i++) { 284 data.writeString(projection[i]); 285 } 286 data.writeString(selection); 287 if (selectionArgs != null) { 288 length = selectionArgs.length; 289 } else { 290 length = 0; 291 } 292 data.writeInt(length); 293 for (int i = 0; i < length; i++) { 294 data.writeString(selectionArgs[i]); 295 } 296 data.writeString(sortOrder); 297 data.writeStrongBinder(observer.asBinder()); 298 window.writeToParcel(data, 0); 299 300 mRemote.transact(IContentProvider.QUERY_TRANSACTION, data, reply, 0); 301 302 DatabaseUtils.readExceptionFromParcel(reply); 303 304 IBulkCursor bulkCursor = null; 305 IBinder bulkCursorBinder = reply.readStrongBinder(); 306 if (bulkCursorBinder != null) { 307 bulkCursor = BulkCursorNative.asInterface(bulkCursorBinder); 308 } 309 310 data.recycle(); 311 reply.recycle(); 312 313 return bulkCursor; 314 } 315 316 public Cursor query(Uri url, String[] projection, String selection, 317 String[] selectionArgs, String sortOrder) throws RemoteException { 318 //TODO make a pool of windows so we can reuse memory dealers 319 CursorWindow window = new CursorWindow(false /* window will be used remotely */); 320 BulkCursorToCursorAdaptor adaptor = new BulkCursorToCursorAdaptor(); 321 IBulkCursor bulkCursor = bulkQuery(url, projection, selection, selectionArgs, sortOrder, 322 adaptor.getObserver(), window); 323 324 if (bulkCursor == null) { 325 return null; 326 } 327 adaptor.set(bulkCursor); 328 return adaptor; 329 } 330 331 public String getType(Uri url) throws RemoteException 332 { 333 Parcel data = Parcel.obtain(); 334 Parcel reply = Parcel.obtain(); 335 336 data.writeInterfaceToken(IContentProvider.descriptor); 337 338 url.writeToParcel(data, 0); 339 340 mRemote.transact(IContentProvider.GET_TYPE_TRANSACTION, data, reply, 0); 341 342 DatabaseUtils.readExceptionFromParcel(reply); 343 String out = reply.readString(); 344 345 data.recycle(); 346 reply.recycle(); 347 348 return out; 349 } 350 351 public Uri insert(Uri url, ContentValues values) throws RemoteException 352 { 353 Parcel data = Parcel.obtain(); 354 Parcel reply = Parcel.obtain(); 355 356 data.writeInterfaceToken(IContentProvider.descriptor); 357 358 url.writeToParcel(data, 0); 359 values.writeToParcel(data, 0); 360 361 mRemote.transact(IContentProvider.INSERT_TRANSACTION, data, reply, 0); 362 363 DatabaseUtils.readExceptionFromParcel(reply); 364 Uri out = Uri.CREATOR.createFromParcel(reply); 365 366 data.recycle(); 367 reply.recycle(); 368 369 return out; 370 } 371 372 public int bulkInsert(Uri url, ContentValues[] values) throws RemoteException { 373 Parcel data = Parcel.obtain(); 374 Parcel reply = Parcel.obtain(); 375 376 data.writeInterfaceToken(IContentProvider.descriptor); 377 378 url.writeToParcel(data, 0); 379 data.writeTypedArray(values, 0); 380 381 mRemote.transact(IContentProvider.BULK_INSERT_TRANSACTION, data, reply, 0); 382 383 DatabaseUtils.readExceptionFromParcel(reply); 384 int count = reply.readInt(); 385 386 data.recycle(); 387 reply.recycle(); 388 389 return count; 390 } 391 392 public ContentProviderResult[] applyBatch(ArrayList<ContentProviderOperation> operations) 393 throws RemoteException, OperationApplicationException { 394 Parcel data = Parcel.obtain(); 395 Parcel reply = Parcel.obtain(); 396 397 data.writeInterfaceToken(IContentProvider.descriptor); 398 data.writeInt(operations.size()); 399 for (ContentProviderOperation operation : operations) { 400 operation.writeToParcel(data, 0); 401 } 402 mRemote.transact(IContentProvider.APPLY_BATCH_TRANSACTION, data, reply, 0); 403 404 DatabaseUtils.readExceptionWithOperationApplicationExceptionFromParcel(reply); 405 final ContentProviderResult[] results = 406 reply.createTypedArray(ContentProviderResult.CREATOR); 407 408 data.recycle(); 409 reply.recycle(); 410 411 return results; 412 } 413 414 public int delete(Uri url, String selection, String[] selectionArgs) 415 throws RemoteException { 416 Parcel data = Parcel.obtain(); 417 Parcel reply = Parcel.obtain(); 418 419 data.writeInterfaceToken(IContentProvider.descriptor); 420 421 url.writeToParcel(data, 0); 422 data.writeString(selection); 423 data.writeStringArray(selectionArgs); 424 425 mRemote.transact(IContentProvider.DELETE_TRANSACTION, data, reply, 0); 426 427 DatabaseUtils.readExceptionFromParcel(reply); 428 int count = reply.readInt(); 429 430 data.recycle(); 431 reply.recycle(); 432 433 return count; 434 } 435 436 public int update(Uri url, ContentValues values, String selection, 437 String[] selectionArgs) throws RemoteException { 438 Parcel data = Parcel.obtain(); 439 Parcel reply = Parcel.obtain(); 440 441 data.writeInterfaceToken(IContentProvider.descriptor); 442 443 url.writeToParcel(data, 0); 444 values.writeToParcel(data, 0); 445 data.writeString(selection); 446 data.writeStringArray(selectionArgs); 447 448 mRemote.transact(IContentProvider.UPDATE_TRANSACTION, data, reply, 0); 449 450 DatabaseUtils.readExceptionFromParcel(reply); 451 int count = reply.readInt(); 452 453 data.recycle(); 454 reply.recycle(); 455 456 return count; 457 } 458 459 public ParcelFileDescriptor openFile(Uri url, String mode) 460 throws RemoteException, FileNotFoundException { 461 Parcel data = Parcel.obtain(); 462 Parcel reply = Parcel.obtain(); 463 464 data.writeInterfaceToken(IContentProvider.descriptor); 465 466 url.writeToParcel(data, 0); 467 data.writeString(mode); 468 469 mRemote.transact(IContentProvider.OPEN_FILE_TRANSACTION, data, reply, 0); 470 471 DatabaseUtils.readExceptionWithFileNotFoundExceptionFromParcel(reply); 472 int has = reply.readInt(); 473 ParcelFileDescriptor fd = has != 0 ? reply.readFileDescriptor() : null; 474 475 data.recycle(); 476 reply.recycle(); 477 478 return fd; 479 } 480 481 public AssetFileDescriptor openAssetFile(Uri url, String mode) 482 throws RemoteException, FileNotFoundException { 483 Parcel data = Parcel.obtain(); 484 Parcel reply = Parcel.obtain(); 485 486 data.writeInterfaceToken(IContentProvider.descriptor); 487 488 url.writeToParcel(data, 0); 489 data.writeString(mode); 490 491 mRemote.transact(IContentProvider.OPEN_ASSET_FILE_TRANSACTION, data, reply, 0); 492 493 DatabaseUtils.readExceptionWithFileNotFoundExceptionFromParcel(reply); 494 int has = reply.readInt(); 495 AssetFileDescriptor fd = has != 0 496 ? AssetFileDescriptor.CREATOR.createFromParcel(reply) : null; 497 498 data.recycle(); 499 reply.recycle(); 500 501 return fd; 502 } 503 504 public Bundle call(String method, String request, Bundle args) 505 throws RemoteException { 506 Parcel data = Parcel.obtain(); 507 Parcel reply = Parcel.obtain(); 508 509 data.writeInterfaceToken(IContentProvider.descriptor); 510 511 data.writeString(method); 512 data.writeString(request); 513 data.writeBundle(args); 514 515 mRemote.transact(IContentProvider.CALL_TRANSACTION, data, reply, 0); 516 517 DatabaseUtils.readExceptionFromParcel(reply); 518 return reply.readBundle(); 519 } 520 521 private IBinder mRemote; 522} 523