ContentProviderNative.java revision c21b5a019c1da00b6d861cd2859e3c349a44b3a7
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.BulkCursorDescriptor; 21import android.database.BulkCursorNative; 22import android.database.BulkCursorToCursorAdaptor; 23import android.database.Cursor; 24import android.database.CursorToBulkCursorAdaptor; 25import android.database.DatabaseUtils; 26import android.database.IBulkCursor; 27import android.database.IContentObserver; 28import android.net.Uri; 29import android.os.Binder; 30import android.os.Bundle; 31import android.os.RemoteException; 32import android.os.IBinder; 33import android.os.ICancellationSignal; 34import android.os.Parcel; 35import android.os.ParcelFileDescriptor; 36import android.os.Parcelable; 37 38import java.io.FileNotFoundException; 39import java.util.ArrayList; 40 41/** 42 * {@hide} 43 */ 44abstract public class ContentProviderNative extends Binder implements IContentProvider { 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 /** 69 * Gets the name of the content provider. 70 * Should probably be part of the {@link IContentProvider} interface. 71 * @return The content provider name. 72 */ 73 public abstract String getProviderName(); 74 75 @Override 76 public boolean onTransact(int code, Parcel data, Parcel reply, int flags) 77 throws RemoteException { 78 try { 79 switch (code) { 80 case QUERY_TRANSACTION: 81 { 82 data.enforceInterface(IContentProvider.descriptor); 83 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 // String selection, String[] selectionArgs... 97 String selection = data.readString(); 98 num = data.readInt(); 99 String[] selectionArgs = null; 100 if (num > 0) { 101 selectionArgs = new String[num]; 102 for (int i = 0; i < num; i++) { 103 selectionArgs[i] = data.readString(); 104 } 105 } 106 107 String sortOrder = data.readString(); 108 IContentObserver observer = IContentObserver.Stub.asInterface( 109 data.readStrongBinder()); 110 ICancellationSignal cancellationSignal = ICancellationSignal.Stub.asInterface( 111 data.readStrongBinder()); 112 113 Cursor cursor = query(url, projection, selection, selectionArgs, sortOrder, 114 cancellationSignal); 115 if (cursor != null) { 116 try { 117 CursorToBulkCursorAdaptor adaptor = new CursorToBulkCursorAdaptor( 118 cursor, observer, getProviderName()); 119 BulkCursorDescriptor d = adaptor.getBulkCursorDescriptor(); 120 cursor = null; 121 122 reply.writeNoException(); 123 reply.writeInt(1); 124 d.writeToParcel(reply, Parcelable.PARCELABLE_WRITE_RETURN_VALUE); 125 } finally { 126 // Close cursor if an exception was thrown while constructing the adaptor. 127 if (cursor != null) { 128 cursor.close(); 129 } 130 } 131 } else { 132 reply.writeNoException(); 133 reply.writeInt(0); 134 } 135 136 return true; 137 } 138 139 case GET_TYPE_TRANSACTION: 140 { 141 data.enforceInterface(IContentProvider.descriptor); 142 Uri url = Uri.CREATOR.createFromParcel(data); 143 String type = getType(url); 144 reply.writeNoException(); 145 reply.writeString(type); 146 147 return true; 148 } 149 150 case INSERT_TRANSACTION: 151 { 152 data.enforceInterface(IContentProvider.descriptor); 153 Uri url = Uri.CREATOR.createFromParcel(data); 154 ContentValues values = ContentValues.CREATOR.createFromParcel(data); 155 156 Uri out = insert(url, values); 157 reply.writeNoException(); 158 Uri.writeToParcel(reply, out); 159 return true; 160 } 161 162 case BULK_INSERT_TRANSACTION: 163 { 164 data.enforceInterface(IContentProvider.descriptor); 165 Uri url = Uri.CREATOR.createFromParcel(data); 166 ContentValues[] values = data.createTypedArray(ContentValues.CREATOR); 167 168 int count = bulkInsert(url, values); 169 reply.writeNoException(); 170 reply.writeInt(count); 171 return true; 172 } 173 174 case APPLY_BATCH_TRANSACTION: 175 { 176 data.enforceInterface(IContentProvider.descriptor); 177 final int numOperations = data.readInt(); 178 final ArrayList<ContentProviderOperation> operations = 179 new ArrayList<ContentProviderOperation>(numOperations); 180 for (int i = 0; i < numOperations; i++) { 181 operations.add(i, ContentProviderOperation.CREATOR.createFromParcel(data)); 182 } 183 final ContentProviderResult[] results = applyBatch(operations); 184 reply.writeNoException(); 185 reply.writeTypedArray(results, 0); 186 return true; 187 } 188 189 case DELETE_TRANSACTION: 190 { 191 data.enforceInterface(IContentProvider.descriptor); 192 Uri url = Uri.CREATOR.createFromParcel(data); 193 String selection = data.readString(); 194 String[] selectionArgs = data.readStringArray(); 195 196 int count = delete(url, selection, selectionArgs); 197 198 reply.writeNoException(); 199 reply.writeInt(count); 200 return true; 201 } 202 203 case UPDATE_TRANSACTION: 204 { 205 data.enforceInterface(IContentProvider.descriptor); 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(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 Uri url = Uri.CREATOR.createFromParcel(data); 222 String mode = data.readString(); 223 224 ParcelFileDescriptor fd; 225 fd = openFile(url, mode); 226 reply.writeNoException(); 227 if (fd != null) { 228 reply.writeInt(1); 229 fd.writeToParcel(reply, 230 Parcelable.PARCELABLE_WRITE_RETURN_VALUE); 231 } else { 232 reply.writeInt(0); 233 } 234 return true; 235 } 236 237 case OPEN_ASSET_FILE_TRANSACTION: 238 { 239 data.enforceInterface(IContentProvider.descriptor); 240 Uri url = Uri.CREATOR.createFromParcel(data); 241 String mode = data.readString(); 242 243 AssetFileDescriptor fd; 244 fd = openAssetFile(url, mode); 245 reply.writeNoException(); 246 if (fd != null) { 247 reply.writeInt(1); 248 fd.writeToParcel(reply, 249 Parcelable.PARCELABLE_WRITE_RETURN_VALUE); 250 } else { 251 reply.writeInt(0); 252 } 253 return true; 254 } 255 256 case CALL_TRANSACTION: 257 { 258 data.enforceInterface(IContentProvider.descriptor); 259 260 String method = data.readString(); 261 String stringArg = data.readString(); 262 Bundle args = data.readBundle(); 263 264 Bundle responseBundle = call(method, stringArg, args); 265 266 reply.writeNoException(); 267 reply.writeBundle(responseBundle); 268 return true; 269 } 270 271 case GET_STREAM_TYPES_TRANSACTION: 272 { 273 data.enforceInterface(IContentProvider.descriptor); 274 Uri url = Uri.CREATOR.createFromParcel(data); 275 String mimeTypeFilter = data.readString(); 276 String[] types = getStreamTypes(url, mimeTypeFilter); 277 reply.writeNoException(); 278 reply.writeStringArray(types); 279 280 return true; 281 } 282 283 case OPEN_TYPED_ASSET_FILE_TRANSACTION: 284 { 285 data.enforceInterface(IContentProvider.descriptor); 286 Uri url = Uri.CREATOR.createFromParcel(data); 287 String mimeType = data.readString(); 288 Bundle opts = data.readBundle(); 289 290 AssetFileDescriptor fd; 291 fd = openTypedAssetFile(url, mimeType, opts); 292 reply.writeNoException(); 293 if (fd != null) { 294 reply.writeInt(1); 295 fd.writeToParcel(reply, 296 Parcelable.PARCELABLE_WRITE_RETURN_VALUE); 297 } else { 298 reply.writeInt(0); 299 } 300 return true; 301 } 302 303 case CREATE_CANCELATION_SIGNAL_TRANSACTION: 304 { 305 data.enforceInterface(IContentProvider.descriptor); 306 307 ICancellationSignal cancellationSignal = createCancellationSignal(); 308 reply.writeNoException(); 309 reply.writeStrongBinder(cancellationSignal.asBinder()); 310 return true; 311 } 312 } 313 } catch (Exception e) { 314 DatabaseUtils.writeExceptionToParcel(reply, e); 315 return true; 316 } 317 318 return super.onTransact(code, data, reply, flags); 319 } 320 321 public IBinder asBinder() 322 { 323 return this; 324 } 325} 326 327 328final class ContentProviderProxy implements IContentProvider 329{ 330 public ContentProviderProxy(IBinder remote) 331 { 332 mRemote = remote; 333 } 334 335 public IBinder asBinder() 336 { 337 return mRemote; 338 } 339 340 public Cursor query(Uri url, String[] projection, String selection, 341 String[] selectionArgs, String sortOrder, ICancellationSignal cancellationSignal) 342 throws RemoteException { 343 BulkCursorToCursorAdaptor adaptor = new BulkCursorToCursorAdaptor(); 344 Parcel data = Parcel.obtain(); 345 Parcel reply = Parcel.obtain(); 346 try { 347 data.writeInterfaceToken(IContentProvider.descriptor); 348 349 url.writeToParcel(data, 0); 350 int length = 0; 351 if (projection != null) { 352 length = projection.length; 353 } 354 data.writeInt(length); 355 for (int i = 0; i < length; i++) { 356 data.writeString(projection[i]); 357 } 358 data.writeString(selection); 359 if (selectionArgs != null) { 360 length = selectionArgs.length; 361 } else { 362 length = 0; 363 } 364 data.writeInt(length); 365 for (int i = 0; i < length; i++) { 366 data.writeString(selectionArgs[i]); 367 } 368 data.writeString(sortOrder); 369 data.writeStrongBinder(adaptor.getObserver().asBinder()); 370 data.writeStrongBinder(cancellationSignal != null ? cancellationSignal.asBinder() : null); 371 372 mRemote.transact(IContentProvider.QUERY_TRANSACTION, data, reply, 0); 373 374 DatabaseUtils.readExceptionFromParcel(reply); 375 376 if (reply.readInt() != 0) { 377 BulkCursorDescriptor d = BulkCursorDescriptor.CREATOR.createFromParcel(reply); 378 adaptor.initialize(d); 379 } else { 380 adaptor.close(); 381 adaptor = null; 382 } 383 return adaptor; 384 } catch (RemoteException ex) { 385 adaptor.close(); 386 throw ex; 387 } catch (RuntimeException ex) { 388 adaptor.close(); 389 throw ex; 390 } finally { 391 data.recycle(); 392 reply.recycle(); 393 } 394 } 395 396 public String getType(Uri url) throws RemoteException 397 { 398 Parcel data = Parcel.obtain(); 399 Parcel reply = Parcel.obtain(); 400 try { 401 data.writeInterfaceToken(IContentProvider.descriptor); 402 403 url.writeToParcel(data, 0); 404 405 mRemote.transact(IContentProvider.GET_TYPE_TRANSACTION, data, reply, 0); 406 407 DatabaseUtils.readExceptionFromParcel(reply); 408 String out = reply.readString(); 409 return out; 410 } finally { 411 data.recycle(); 412 reply.recycle(); 413 } 414 } 415 416 public Uri insert(Uri url, ContentValues values) throws RemoteException 417 { 418 Parcel data = Parcel.obtain(); 419 Parcel reply = Parcel.obtain(); 420 try { 421 data.writeInterfaceToken(IContentProvider.descriptor); 422 423 url.writeToParcel(data, 0); 424 values.writeToParcel(data, 0); 425 426 mRemote.transact(IContentProvider.INSERT_TRANSACTION, data, reply, 0); 427 428 DatabaseUtils.readExceptionFromParcel(reply); 429 Uri out = Uri.CREATOR.createFromParcel(reply); 430 return out; 431 } finally { 432 data.recycle(); 433 reply.recycle(); 434 } 435 } 436 437 public int bulkInsert(Uri url, ContentValues[] values) throws RemoteException { 438 Parcel data = Parcel.obtain(); 439 Parcel reply = Parcel.obtain(); 440 try { 441 data.writeInterfaceToken(IContentProvider.descriptor); 442 443 url.writeToParcel(data, 0); 444 data.writeTypedArray(values, 0); 445 446 mRemote.transact(IContentProvider.BULK_INSERT_TRANSACTION, data, reply, 0); 447 448 DatabaseUtils.readExceptionFromParcel(reply); 449 int count = reply.readInt(); 450 return count; 451 } finally { 452 data.recycle(); 453 reply.recycle(); 454 } 455 } 456 457 public ContentProviderResult[] applyBatch(ArrayList<ContentProviderOperation> operations) 458 throws RemoteException, OperationApplicationException { 459 Parcel data = Parcel.obtain(); 460 Parcel reply = Parcel.obtain(); 461 try { 462 data.writeInterfaceToken(IContentProvider.descriptor); 463 data.writeInt(operations.size()); 464 for (ContentProviderOperation operation : operations) { 465 operation.writeToParcel(data, 0); 466 } 467 mRemote.transact(IContentProvider.APPLY_BATCH_TRANSACTION, data, reply, 0); 468 469 DatabaseUtils.readExceptionWithOperationApplicationExceptionFromParcel(reply); 470 final ContentProviderResult[] results = 471 reply.createTypedArray(ContentProviderResult.CREATOR); 472 return results; 473 } finally { 474 data.recycle(); 475 reply.recycle(); 476 } 477 } 478 479 public int delete(Uri url, String selection, String[] selectionArgs) 480 throws RemoteException { 481 Parcel data = Parcel.obtain(); 482 Parcel reply = Parcel.obtain(); 483 try { 484 data.writeInterfaceToken(IContentProvider.descriptor); 485 486 url.writeToParcel(data, 0); 487 data.writeString(selection); 488 data.writeStringArray(selectionArgs); 489 490 mRemote.transact(IContentProvider.DELETE_TRANSACTION, data, reply, 0); 491 492 DatabaseUtils.readExceptionFromParcel(reply); 493 int count = reply.readInt(); 494 return count; 495 } finally { 496 data.recycle(); 497 reply.recycle(); 498 } 499 } 500 501 public int update(Uri url, ContentValues values, String selection, 502 String[] selectionArgs) throws RemoteException { 503 Parcel data = Parcel.obtain(); 504 Parcel reply = Parcel.obtain(); 505 try { 506 data.writeInterfaceToken(IContentProvider.descriptor); 507 508 url.writeToParcel(data, 0); 509 values.writeToParcel(data, 0); 510 data.writeString(selection); 511 data.writeStringArray(selectionArgs); 512 513 mRemote.transact(IContentProvider.UPDATE_TRANSACTION, data, reply, 0); 514 515 DatabaseUtils.readExceptionFromParcel(reply); 516 int count = reply.readInt(); 517 return count; 518 } finally { 519 data.recycle(); 520 reply.recycle(); 521 } 522 } 523 524 public ParcelFileDescriptor openFile(Uri url, String mode) 525 throws RemoteException, FileNotFoundException { 526 Parcel data = Parcel.obtain(); 527 Parcel reply = Parcel.obtain(); 528 try { 529 data.writeInterfaceToken(IContentProvider.descriptor); 530 531 url.writeToParcel(data, 0); 532 data.writeString(mode); 533 534 mRemote.transact(IContentProvider.OPEN_FILE_TRANSACTION, data, reply, 0); 535 536 DatabaseUtils.readExceptionWithFileNotFoundExceptionFromParcel(reply); 537 int has = reply.readInt(); 538 ParcelFileDescriptor fd = has != 0 ? reply.readFileDescriptor() : null; 539 return fd; 540 } finally { 541 data.recycle(); 542 reply.recycle(); 543 } 544 } 545 546 public AssetFileDescriptor openAssetFile(Uri url, String mode) 547 throws RemoteException, FileNotFoundException { 548 Parcel data = Parcel.obtain(); 549 Parcel reply = Parcel.obtain(); 550 try { 551 data.writeInterfaceToken(IContentProvider.descriptor); 552 553 url.writeToParcel(data, 0); 554 data.writeString(mode); 555 556 mRemote.transact(IContentProvider.OPEN_ASSET_FILE_TRANSACTION, data, reply, 0); 557 558 DatabaseUtils.readExceptionWithFileNotFoundExceptionFromParcel(reply); 559 int has = reply.readInt(); 560 AssetFileDescriptor fd = has != 0 561 ? AssetFileDescriptor.CREATOR.createFromParcel(reply) : null; 562 return fd; 563 } finally { 564 data.recycle(); 565 reply.recycle(); 566 } 567 } 568 569 public Bundle call(String method, String request, Bundle args) 570 throws RemoteException { 571 Parcel data = Parcel.obtain(); 572 Parcel reply = Parcel.obtain(); 573 try { 574 data.writeInterfaceToken(IContentProvider.descriptor); 575 576 data.writeString(method); 577 data.writeString(request); 578 data.writeBundle(args); 579 580 mRemote.transact(IContentProvider.CALL_TRANSACTION, data, reply, 0); 581 582 DatabaseUtils.readExceptionFromParcel(reply); 583 Bundle bundle = reply.readBundle(); 584 return bundle; 585 } finally { 586 data.recycle(); 587 reply.recycle(); 588 } 589 } 590 591 public String[] getStreamTypes(Uri url, String mimeTypeFilter) throws RemoteException 592 { 593 Parcel data = Parcel.obtain(); 594 Parcel reply = Parcel.obtain(); 595 try { 596 data.writeInterfaceToken(IContentProvider.descriptor); 597 598 url.writeToParcel(data, 0); 599 data.writeString(mimeTypeFilter); 600 601 mRemote.transact(IContentProvider.GET_STREAM_TYPES_TRANSACTION, data, reply, 0); 602 603 DatabaseUtils.readExceptionFromParcel(reply); 604 String[] out = reply.createStringArray(); 605 return out; 606 } finally { 607 data.recycle(); 608 reply.recycle(); 609 } 610 } 611 612 public AssetFileDescriptor openTypedAssetFile(Uri url, String mimeType, Bundle opts) 613 throws RemoteException, FileNotFoundException { 614 Parcel data = Parcel.obtain(); 615 Parcel reply = Parcel.obtain(); 616 try { 617 data.writeInterfaceToken(IContentProvider.descriptor); 618 619 url.writeToParcel(data, 0); 620 data.writeString(mimeType); 621 data.writeBundle(opts); 622 623 mRemote.transact(IContentProvider.OPEN_TYPED_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 public ICancellationSignal createCancellationSignal() throws RemoteException { 637 Parcel data = Parcel.obtain(); 638 Parcel reply = Parcel.obtain(); 639 try { 640 data.writeInterfaceToken(IContentProvider.descriptor); 641 642 mRemote.transact(IContentProvider.CREATE_CANCELATION_SIGNAL_TRANSACTION, 643 data, reply, 0); 644 645 DatabaseUtils.readExceptionFromParcel(reply); 646 ICancellationSignal cancellationSignal = ICancellationSignal.Stub.asInterface( 647 reply.readStrongBinder()); 648 return cancellationSignal; 649 } finally { 650 data.recycle(); 651 reply.recycle(); 652 } 653 } 654 655 private IBinder mRemote; 656} 657