ContentProviderNative.java revision 6a8d5332f00bdfade6674b312e7166940aa28348
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 BULK_INSERT_ENTITIES_TRANSACTION: 158 { 159 data.enforceInterface(IContentProvider.descriptor); 160 Uri uri = Uri.CREATOR.createFromParcel(data); 161 String className = data.readString(); 162 Class entityClass = Class.forName(className); 163 int numEntities = data.readInt(); 164 Entity[] entities = new Entity[numEntities]; 165 for (int i = 0; i < numEntities; i++) { 166 entities[i] = (Entity) data.readParcelable(entityClass.getClassLoader()); 167 } 168 Uri[] uris = bulkInsertEntities(uri, entities); 169 reply.writeNoException(); 170 reply.writeTypedArray(uris, 0); 171 return true; 172 } 173 174 case BULK_UPDATE_ENTITIES_TRANSACTION: 175 { 176 data.enforceInterface(IContentProvider.descriptor); 177 Uri uri = Uri.CREATOR.createFromParcel(data); 178 String className = data.readString(); 179 Class entityClass = Class.forName(className); 180 int numEntities = data.readInt(); 181 Entity[] entities = new Entity[numEntities]; 182 for (int i = 0; i < numEntities; i++) { 183 entities[i] = (Entity) data.readParcelable(entityClass.getClassLoader()); 184 } 185 int[] counts = bulkUpdateEntities(uri, entities); 186 reply.writeNoException(); 187 reply.writeIntArray(counts); 188 return true; 189 } 190 191 case DELETE_TRANSACTION: 192 { 193 data.enforceInterface(IContentProvider.descriptor); 194 Uri url = Uri.CREATOR.createFromParcel(data); 195 String selection = data.readString(); 196 String[] selectionArgs = data.readStringArray(); 197 198 int count = delete(url, selection, selectionArgs); 199 200 reply.writeNoException(); 201 reply.writeInt(count); 202 return true; 203 } 204 205 case UPDATE_TRANSACTION: 206 { 207 data.enforceInterface(IContentProvider.descriptor); 208 Uri url = Uri.CREATOR.createFromParcel(data); 209 ContentValues values = ContentValues.CREATOR.createFromParcel(data); 210 String selection = data.readString(); 211 String[] selectionArgs = data.readStringArray(); 212 213 int count = update(url, values, selection, selectionArgs); 214 215 reply.writeNoException(); 216 reply.writeInt(count); 217 return true; 218 } 219 220 case OPEN_FILE_TRANSACTION: 221 { 222 data.enforceInterface(IContentProvider.descriptor); 223 Uri url = Uri.CREATOR.createFromParcel(data); 224 String mode = data.readString(); 225 226 ParcelFileDescriptor fd; 227 fd = openFile(url, mode); 228 reply.writeNoException(); 229 if (fd != null) { 230 reply.writeInt(1); 231 fd.writeToParcel(reply, 232 Parcelable.PARCELABLE_WRITE_RETURN_VALUE); 233 } else { 234 reply.writeInt(0); 235 } 236 return true; 237 } 238 239 case OPEN_ASSET_FILE_TRANSACTION: 240 { 241 data.enforceInterface(IContentProvider.descriptor); 242 Uri url = Uri.CREATOR.createFromParcel(data); 243 String mode = data.readString(); 244 245 AssetFileDescriptor fd; 246 fd = openAssetFile(url, mode); 247 reply.writeNoException(); 248 if (fd != null) { 249 reply.writeInt(1); 250 fd.writeToParcel(reply, 251 Parcelable.PARCELABLE_WRITE_RETURN_VALUE); 252 } else { 253 reply.writeInt(0); 254 } 255 return true; 256 } 257 } 258 } catch (Exception e) { 259 DatabaseUtils.writeExceptionToParcel(reply, e); 260 return true; 261 } 262 263 return super.onTransact(code, data, reply, flags); 264 } 265 266 private class IEntityIteratorImpl extends IEntityIterator.Stub { 267 private final EntityIterator mEntityIterator; 268 269 IEntityIteratorImpl(EntityIterator iterator) { 270 mEntityIterator = iterator; 271 } 272 public boolean hasNext() throws RemoteException { 273 return mEntityIterator.hasNext(); 274 } 275 276 public Entity next() throws RemoteException { 277 return mEntityIterator.next(); 278 } 279 280 public void close() throws RemoteException { 281 mEntityIterator.close(); 282 } 283 } 284 285 public IBinder asBinder() 286 { 287 return this; 288 } 289} 290 291 292final class ContentProviderProxy implements IContentProvider 293{ 294 public ContentProviderProxy(IBinder remote) 295 { 296 mRemote = remote; 297 } 298 299 public IBinder asBinder() 300 { 301 return mRemote; 302 } 303 304 public IBulkCursor bulkQuery(Uri url, String[] projection, 305 String selection, String[] selectionArgs, String sortOrder, IContentObserver observer, 306 CursorWindow window) throws RemoteException { 307 Parcel data = Parcel.obtain(); 308 Parcel reply = Parcel.obtain(); 309 310 data.writeInterfaceToken(IContentProvider.descriptor); 311 312 url.writeToParcel(data, 0); 313 int length = 0; 314 if (projection != null) { 315 length = projection.length; 316 } 317 data.writeInt(length); 318 for (int i = 0; i < length; i++) { 319 data.writeString(projection[i]); 320 } 321 data.writeString(selection); 322 if (selectionArgs != null) { 323 length = selectionArgs.length; 324 } else { 325 length = 0; 326 } 327 data.writeInt(length); 328 for (int i = 0; i < length; i++) { 329 data.writeString(selectionArgs[i]); 330 } 331 data.writeString(sortOrder); 332 data.writeStrongBinder(observer.asBinder()); 333 window.writeToParcel(data, 0); 334 335 mRemote.transact(IContentProvider.QUERY_TRANSACTION, data, reply, 0); 336 337 DatabaseUtils.readExceptionFromParcel(reply); 338 339 IBulkCursor bulkCursor = null; 340 IBinder bulkCursorBinder = reply.readStrongBinder(); 341 if (bulkCursorBinder != null) { 342 bulkCursor = BulkCursorNative.asInterface(bulkCursorBinder); 343 } 344 345 data.recycle(); 346 reply.recycle(); 347 348 return bulkCursor; 349 } 350 351 public Cursor query(Uri url, String[] projection, String selection, 352 String[] selectionArgs, String sortOrder) throws RemoteException { 353 //TODO make a pool of windows so we can reuse memory dealers 354 CursorWindow window = new CursorWindow(false /* window will be used remotely */); 355 BulkCursorToCursorAdaptor adaptor = new BulkCursorToCursorAdaptor(); 356 IBulkCursor bulkCursor = bulkQuery(url, projection, selection, selectionArgs, sortOrder, 357 adaptor.getObserver(), window); 358 359 if (bulkCursor == null) { 360 return null; 361 } 362 adaptor.set(bulkCursor); 363 return adaptor; 364 } 365 366 public EntityIterator queryEntities(Uri url, String selection, String[] selectionArgs, 367 String sortOrder) 368 throws RemoteException { 369 Parcel data = Parcel.obtain(); 370 Parcel reply = Parcel.obtain(); 371 372 data.writeInterfaceToken(IContentProvider.descriptor); 373 374 url.writeToParcel(data, 0); 375 data.writeString(selection); 376 data.writeStringArray(selectionArgs); 377 data.writeString(sortOrder); 378 379 mRemote.transact(IContentProvider.QUERY_ENTITIES_TRANSACTION, data, reply, 0); 380 381 DatabaseUtils.readExceptionFromParcel(reply); 382 383 IBinder entityIteratorBinder = reply.readStrongBinder(); 384 385 data.recycle(); 386 reply.recycle(); 387 388 return new RemoteEntityIterator(IEntityIterator.Stub.asInterface(entityIteratorBinder)); 389 } 390 391 static class RemoteEntityIterator implements EntityIterator { 392 private final IEntityIterator mEntityIterator; 393 RemoteEntityIterator(IEntityIterator entityIterator) { 394 mEntityIterator = entityIterator; 395 } 396 397 public boolean hasNext() throws RemoteException { 398 return mEntityIterator.hasNext(); 399 } 400 401 public Entity next() throws RemoteException { 402 return mEntityIterator.next(); 403 } 404 405 public void close() { 406 try { 407 mEntityIterator.close(); 408 } catch (RemoteException e) { 409 // doesn't matter 410 } 411 } 412 } 413 414 public String getType(Uri url) throws RemoteException 415 { 416 Parcel data = Parcel.obtain(); 417 Parcel reply = Parcel.obtain(); 418 419 data.writeInterfaceToken(IContentProvider.descriptor); 420 421 url.writeToParcel(data, 0); 422 423 mRemote.transact(IContentProvider.GET_TYPE_TRANSACTION, data, reply, 0); 424 425 DatabaseUtils.readExceptionFromParcel(reply); 426 String out = reply.readString(); 427 428 data.recycle(); 429 reply.recycle(); 430 431 return out; 432 } 433 434 public Uri insert(Uri url, ContentValues values) throws RemoteException 435 { 436 Parcel data = Parcel.obtain(); 437 Parcel reply = Parcel.obtain(); 438 439 data.writeInterfaceToken(IContentProvider.descriptor); 440 441 url.writeToParcel(data, 0); 442 values.writeToParcel(data, 0); 443 444 mRemote.transact(IContentProvider.INSERT_TRANSACTION, data, reply, 0); 445 446 DatabaseUtils.readExceptionFromParcel(reply); 447 Uri out = Uri.CREATOR.createFromParcel(reply); 448 449 data.recycle(); 450 reply.recycle(); 451 452 return out; 453 } 454 455 public int bulkInsert(Uri url, ContentValues[] values) throws RemoteException { 456 Parcel data = Parcel.obtain(); 457 Parcel reply = Parcel.obtain(); 458 459 data.writeInterfaceToken(IContentProvider.descriptor); 460 461 url.writeToParcel(data, 0); 462 data.writeTypedArray(values, 0); 463 464 mRemote.transact(IContentProvider.BULK_INSERT_TRANSACTION, data, reply, 0); 465 466 DatabaseUtils.readExceptionFromParcel(reply); 467 int count = reply.readInt(); 468 469 data.recycle(); 470 reply.recycle(); 471 472 return count; 473 } 474 475 public Uri[] bulkInsertEntities(Uri uri, Entity[] entities) throws RemoteException { 476 Parcel data = Parcel.obtain(); 477 Parcel reply = Parcel.obtain(); 478 479 data.writeInterfaceToken(IContentProvider.descriptor); 480 uri.writeToParcel(data, 0); 481 data.writeString(entities[0].getClass().getName()); 482 data.writeInt(entities.length); 483 for (Entity entity : entities) { 484 data.writeParcelable(entity, 0); 485 } 486 487 mRemote.transact(IContentProvider.BULK_INSERT_ENTITIES_TRANSACTION, data, reply, 0); 488 489 DatabaseUtils.readExceptionFromParcel(reply); 490 Uri[] results = new Uri[entities.length]; 491 reply.readTypedArray(results, Uri.CREATOR); 492 493 data.recycle(); 494 reply.recycle(); 495 496 return results; 497 } 498 499 public int[] bulkUpdateEntities(Uri uri, Entity[] entities) throws RemoteException { 500 Parcel data = Parcel.obtain(); 501 Parcel reply = Parcel.obtain(); 502 503 data.writeInterfaceToken(IContentProvider.descriptor); 504 uri.writeToParcel(data, 0); 505 data.writeString(entities[0].getClass().getName()); 506 data.writeInt(entities.length); 507 for (Entity entity : entities) { 508 data.writeParcelable(entity, 0); 509 } 510 511 mRemote.transact(IContentProvider.BULK_UPDATE_ENTITIES_TRANSACTION, data, reply, 0); 512 513 DatabaseUtils.readExceptionFromParcel(reply); 514 int[] results = new int[entities.length]; 515 reply.readIntArray(results); 516 517 data.recycle(); 518 reply.recycle(); 519 520 return results; 521 } 522 523 public int delete(Uri url, String selection, String[] selectionArgs) 524 throws RemoteException { 525 Parcel data = Parcel.obtain(); 526 Parcel reply = Parcel.obtain(); 527 528 data.writeInterfaceToken(IContentProvider.descriptor); 529 530 url.writeToParcel(data, 0); 531 data.writeString(selection); 532 data.writeStringArray(selectionArgs); 533 534 mRemote.transact(IContentProvider.DELETE_TRANSACTION, data, reply, 0); 535 536 DatabaseUtils.readExceptionFromParcel(reply); 537 int count = reply.readInt(); 538 539 data.recycle(); 540 reply.recycle(); 541 542 return count; 543 } 544 545 public int update(Uri url, ContentValues values, String selection, 546 String[] selectionArgs) throws RemoteException { 547 Parcel data = Parcel.obtain(); 548 Parcel reply = Parcel.obtain(); 549 550 data.writeInterfaceToken(IContentProvider.descriptor); 551 552 url.writeToParcel(data, 0); 553 values.writeToParcel(data, 0); 554 data.writeString(selection); 555 data.writeStringArray(selectionArgs); 556 557 mRemote.transact(IContentProvider.UPDATE_TRANSACTION, data, reply, 0); 558 559 DatabaseUtils.readExceptionFromParcel(reply); 560 int count = reply.readInt(); 561 562 data.recycle(); 563 reply.recycle(); 564 565 return count; 566 } 567 568 public ParcelFileDescriptor openFile(Uri url, String mode) 569 throws RemoteException, FileNotFoundException { 570 Parcel data = Parcel.obtain(); 571 Parcel reply = Parcel.obtain(); 572 573 data.writeInterfaceToken(IContentProvider.descriptor); 574 575 url.writeToParcel(data, 0); 576 data.writeString(mode); 577 578 mRemote.transact(IContentProvider.OPEN_FILE_TRANSACTION, data, reply, 0); 579 580 DatabaseUtils.readExceptionWithFileNotFoundExceptionFromParcel(reply); 581 int has = reply.readInt(); 582 ParcelFileDescriptor fd = has != 0 ? reply.readFileDescriptor() : null; 583 584 data.recycle(); 585 reply.recycle(); 586 587 return fd; 588 } 589 590 public AssetFileDescriptor openAssetFile(Uri url, String mode) 591 throws RemoteException, FileNotFoundException { 592 Parcel data = Parcel.obtain(); 593 Parcel reply = Parcel.obtain(); 594 595 data.writeInterfaceToken(IContentProvider.descriptor); 596 597 url.writeToParcel(data, 0); 598 data.writeString(mode); 599 600 mRemote.transact(IContentProvider.OPEN_ASSET_FILE_TRANSACTION, data, reply, 0); 601 602 DatabaseUtils.readExceptionWithFileNotFoundExceptionFromParcel(reply); 603 int has = reply.readInt(); 604 AssetFileDescriptor fd = has != 0 605 ? AssetFileDescriptor.CREATOR.createFromParcel(reply) : null; 606 607 data.recycle(); 608 reply.recycle(); 609 610 return fd; 611 } 612 613 private IBinder mRemote; 614} 615 616