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