ContentProviderNative.java revision 03d9490758c9318cee6d14d3cc5007556dce92d0
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 close() throws RemoteException { 285 mEntityIterator.close(); 286 } 287 } 288 289 public IBinder asBinder() 290 { 291 return this; 292 } 293} 294 295 296final class ContentProviderProxy implements IContentProvider 297{ 298 public ContentProviderProxy(IBinder remote) 299 { 300 mRemote = remote; 301 } 302 303 public IBinder asBinder() 304 { 305 return mRemote; 306 } 307 308 public IBulkCursor bulkQuery(Uri url, String[] projection, 309 String selection, String[] selectionArgs, String sortOrder, IContentObserver observer, 310 CursorWindow window) throws RemoteException { 311 Parcel data = Parcel.obtain(); 312 Parcel reply = Parcel.obtain(); 313 314 data.writeInterfaceToken(IContentProvider.descriptor); 315 316 url.writeToParcel(data, 0); 317 int length = 0; 318 if (projection != null) { 319 length = projection.length; 320 } 321 data.writeInt(length); 322 for (int i = 0; i < length; i++) { 323 data.writeString(projection[i]); 324 } 325 data.writeString(selection); 326 if (selectionArgs != null) { 327 length = selectionArgs.length; 328 } else { 329 length = 0; 330 } 331 data.writeInt(length); 332 for (int i = 0; i < length; i++) { 333 data.writeString(selectionArgs[i]); 334 } 335 data.writeString(sortOrder); 336 data.writeStrongBinder(observer.asBinder()); 337 window.writeToParcel(data, 0); 338 339 mRemote.transact(IContentProvider.QUERY_TRANSACTION, data, reply, 0); 340 341 DatabaseUtils.readExceptionFromParcel(reply); 342 343 IBulkCursor bulkCursor = null; 344 IBinder bulkCursorBinder = reply.readStrongBinder(); 345 if (bulkCursorBinder != null) { 346 bulkCursor = BulkCursorNative.asInterface(bulkCursorBinder); 347 } 348 349 data.recycle(); 350 reply.recycle(); 351 352 return bulkCursor; 353 } 354 355 public Cursor query(Uri url, String[] projection, String selection, 356 String[] selectionArgs, String sortOrder) throws RemoteException { 357 //TODO make a pool of windows so we can reuse memory dealers 358 CursorWindow window = new CursorWindow(false /* window will be used remotely */); 359 BulkCursorToCursorAdaptor adaptor = new BulkCursorToCursorAdaptor(); 360 IBulkCursor bulkCursor = bulkQuery(url, projection, selection, selectionArgs, sortOrder, 361 adaptor.getObserver(), window); 362 363 if (bulkCursor == null) { 364 return null; 365 } 366 adaptor.set(bulkCursor); 367 return adaptor; 368 } 369 370 public EntityIterator queryEntities(Uri url, String selection, String[] selectionArgs, 371 String sortOrder) 372 throws RemoteException { 373 Parcel data = Parcel.obtain(); 374 Parcel reply = Parcel.obtain(); 375 376 data.writeInterfaceToken(IContentProvider.descriptor); 377 378 url.writeToParcel(data, 0); 379 data.writeString(selection); 380 data.writeStringArray(selectionArgs); 381 data.writeString(sortOrder); 382 383 mRemote.transact(IContentProvider.QUERY_ENTITIES_TRANSACTION, data, reply, 0); 384 385 DatabaseUtils.readExceptionFromParcel(reply); 386 387 IBinder entityIteratorBinder = reply.readStrongBinder(); 388 389 data.recycle(); 390 reply.recycle(); 391 392 return new RemoteEntityIterator(IEntityIterator.Stub.asInterface(entityIteratorBinder)); 393 } 394 395 static class RemoteEntityIterator implements EntityIterator { 396 private final IEntityIterator mEntityIterator; 397 RemoteEntityIterator(IEntityIterator entityIterator) { 398 mEntityIterator = entityIterator; 399 } 400 401 public boolean hasNext() throws RemoteException { 402 return mEntityIterator.hasNext(); 403 } 404 405 public Entity next() throws RemoteException { 406 return mEntityIterator.next(); 407 } 408 409 public void close() { 410 try { 411 mEntityIterator.close(); 412 } catch (RemoteException e) { 413 // doesn't matter 414 } 415 } 416 } 417 418 public String getType(Uri url) throws RemoteException 419 { 420 Parcel data = Parcel.obtain(); 421 Parcel reply = Parcel.obtain(); 422 423 data.writeInterfaceToken(IContentProvider.descriptor); 424 425 url.writeToParcel(data, 0); 426 427 mRemote.transact(IContentProvider.GET_TYPE_TRANSACTION, data, reply, 0); 428 429 DatabaseUtils.readExceptionFromParcel(reply); 430 String out = reply.readString(); 431 432 data.recycle(); 433 reply.recycle(); 434 435 return out; 436 } 437 438 public Uri insert(Uri url, ContentValues values) throws RemoteException 439 { 440 Parcel data = Parcel.obtain(); 441 Parcel reply = Parcel.obtain(); 442 443 data.writeInterfaceToken(IContentProvider.descriptor); 444 445 url.writeToParcel(data, 0); 446 values.writeToParcel(data, 0); 447 448 mRemote.transact(IContentProvider.INSERT_TRANSACTION, data, reply, 0); 449 450 DatabaseUtils.readExceptionFromParcel(reply); 451 Uri out = Uri.CREATOR.createFromParcel(reply); 452 453 data.recycle(); 454 reply.recycle(); 455 456 return out; 457 } 458 459 public int bulkInsert(Uri url, ContentValues[] values) throws RemoteException { 460 Parcel data = Parcel.obtain(); 461 Parcel reply = Parcel.obtain(); 462 463 data.writeInterfaceToken(IContentProvider.descriptor); 464 465 url.writeToParcel(data, 0); 466 data.writeTypedArray(values, 0); 467 468 mRemote.transact(IContentProvider.BULK_INSERT_TRANSACTION, data, reply, 0); 469 470 DatabaseUtils.readExceptionFromParcel(reply); 471 int count = reply.readInt(); 472 473 data.recycle(); 474 reply.recycle(); 475 476 return count; 477 } 478 479 public ContentProviderResult[] applyBatch(ArrayList<ContentProviderOperation> operations) 480 throws RemoteException, OperationApplicationException { 481 Parcel data = Parcel.obtain(); 482 Parcel reply = Parcel.obtain(); 483 484 data.writeInterfaceToken(IContentProvider.descriptor); 485 data.writeInt(operations.size()); 486 for (ContentProviderOperation operation : operations) { 487 operation.writeToParcel(data, 0); 488 } 489 mRemote.transact(IContentProvider.APPLY_BATCH_TRANSACTION, data, reply, 0); 490 491 DatabaseUtils.readExceptionWithOperationApplicationExceptionFromParcel(reply); 492 final ContentProviderResult[] results = 493 reply.createTypedArray(ContentProviderResult.CREATOR); 494 495 data.recycle(); 496 reply.recycle(); 497 498 return results; 499 } 500 501 public Uri insertEntity(Uri uri, Entity entity) throws RemoteException { 502 Parcel data = Parcel.obtain(); 503 Parcel reply = Parcel.obtain(); 504 505 try { 506 data.writeInterfaceToken(IContentProvider.descriptor); 507 uri.writeToParcel(data, 0); 508 data.writeParcelable(entity, 0); 509 510 mRemote.transact(IContentProvider.INSERT_ENTITIES_TRANSACTION, data, reply, 0); 511 512 DatabaseUtils.readExceptionFromParcel(reply); 513 return Uri.CREATOR.createFromParcel(reply); 514 } finally { 515 data.recycle(); 516 reply.recycle(); 517 } 518 } 519 520 public int updateEntity(Uri uri, Entity entity) throws RemoteException { 521 Parcel data = Parcel.obtain(); 522 Parcel reply = Parcel.obtain(); 523 524 try { 525 data.writeInterfaceToken(IContentProvider.descriptor); 526 uri.writeToParcel(data, 0); 527 data.writeParcelable(entity, 0); 528 529 mRemote.transact(IContentProvider.UPDATE_ENTITIES_TRANSACTION, data, reply, 0); 530 531 DatabaseUtils.readExceptionFromParcel(reply); 532 return reply.readInt(); 533 } finally { 534 data.recycle(); 535 reply.recycle(); 536 } 537 } 538 539 public int delete(Uri url, String selection, String[] selectionArgs) 540 throws RemoteException { 541 Parcel data = Parcel.obtain(); 542 Parcel reply = Parcel.obtain(); 543 544 data.writeInterfaceToken(IContentProvider.descriptor); 545 546 url.writeToParcel(data, 0); 547 data.writeString(selection); 548 data.writeStringArray(selectionArgs); 549 550 mRemote.transact(IContentProvider.DELETE_TRANSACTION, data, reply, 0); 551 552 DatabaseUtils.readExceptionFromParcel(reply); 553 int count = reply.readInt(); 554 555 data.recycle(); 556 reply.recycle(); 557 558 return count; 559 } 560 561 public int update(Uri url, ContentValues values, String selection, 562 String[] selectionArgs) throws RemoteException { 563 Parcel data = Parcel.obtain(); 564 Parcel reply = Parcel.obtain(); 565 566 data.writeInterfaceToken(IContentProvider.descriptor); 567 568 url.writeToParcel(data, 0); 569 values.writeToParcel(data, 0); 570 data.writeString(selection); 571 data.writeStringArray(selectionArgs); 572 573 mRemote.transact(IContentProvider.UPDATE_TRANSACTION, data, reply, 0); 574 575 DatabaseUtils.readExceptionFromParcel(reply); 576 int count = reply.readInt(); 577 578 data.recycle(); 579 reply.recycle(); 580 581 return count; 582 } 583 584 public ParcelFileDescriptor openFile(Uri url, String mode) 585 throws RemoteException, FileNotFoundException { 586 Parcel data = Parcel.obtain(); 587 Parcel reply = Parcel.obtain(); 588 589 data.writeInterfaceToken(IContentProvider.descriptor); 590 591 url.writeToParcel(data, 0); 592 data.writeString(mode); 593 594 mRemote.transact(IContentProvider.OPEN_FILE_TRANSACTION, data, reply, 0); 595 596 DatabaseUtils.readExceptionWithFileNotFoundExceptionFromParcel(reply); 597 int has = reply.readInt(); 598 ParcelFileDescriptor fd = has != 0 ? reply.readFileDescriptor() : null; 599 600 data.recycle(); 601 reply.recycle(); 602 603 return fd; 604 } 605 606 public AssetFileDescriptor openAssetFile(Uri url, String mode) 607 throws RemoteException, FileNotFoundException { 608 Parcel data = Parcel.obtain(); 609 Parcel reply = Parcel.obtain(); 610 611 data.writeInterfaceToken(IContentProvider.descriptor); 612 613 url.writeToParcel(data, 0); 614 data.writeString(mode); 615 616 mRemote.transact(IContentProvider.OPEN_ASSET_FILE_TRANSACTION, data, reply, 0); 617 618 DatabaseUtils.readExceptionWithFileNotFoundExceptionFromParcel(reply); 619 int has = reply.readInt(); 620 AssetFileDescriptor fd = has != 0 621 ? AssetFileDescriptor.CREATOR.createFromParcel(reply) : null; 622 623 data.recycle(); 624 reply.recycle(); 625 626 return fd; 627 } 628 629 private IBinder mRemote; 630} 631 632