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