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