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