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