ContentProviderNative.java revision 328c0e7986aa6bb7752ec6de3da9c999920bb55f
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 GET_TYPE_TRANSACTION: 110 { 111 data.enforceInterface(IContentProvider.descriptor); 112 Uri url = Uri.CREATOR.createFromParcel(data); 113 String type = getType(url); 114 reply.writeNoException(); 115 reply.writeString(type); 116 117 return true; 118 } 119 120 case INSERT_TRANSACTION: 121 { 122 data.enforceInterface(IContentProvider.descriptor); 123 Uri url = Uri.CREATOR.createFromParcel(data); 124 ContentValues values = ContentValues.CREATOR.createFromParcel(data); 125 126 Uri out = insert(url, values); 127 reply.writeNoException(); 128 Uri.writeToParcel(reply, out); 129 return true; 130 } 131 132 case BULK_INSERT_TRANSACTION: 133 { 134 data.enforceInterface(IContentProvider.descriptor); 135 Uri url = Uri.CREATOR.createFromParcel(data); 136 ContentValues[] values = data.createTypedArray(ContentValues.CREATOR); 137 138 int count = bulkInsert(url, values); 139 reply.writeNoException(); 140 reply.writeInt(count); 141 return true; 142 } 143 144 case APPLY_BATCH_TRANSACTION: 145 { 146 data.enforceInterface(IContentProvider.descriptor); 147 final int numOperations = data.readInt(); 148 final ArrayList<ContentProviderOperation> operations = 149 new ArrayList<ContentProviderOperation>(numOperations); 150 for (int i = 0; i < numOperations; i++) { 151 operations.add(i, ContentProviderOperation.CREATOR.createFromParcel(data)); 152 } 153 final ContentProviderResult[] results = applyBatch(operations); 154 reply.writeNoException(); 155 reply.writeTypedArray(results, 0); 156 return true; 157 } 158 159 case DELETE_TRANSACTION: 160 { 161 data.enforceInterface(IContentProvider.descriptor); 162 Uri url = Uri.CREATOR.createFromParcel(data); 163 String selection = data.readString(); 164 String[] selectionArgs = data.readStringArray(); 165 166 int count = delete(url, selection, selectionArgs); 167 168 reply.writeNoException(); 169 reply.writeInt(count); 170 return true; 171 } 172 173 case UPDATE_TRANSACTION: 174 { 175 data.enforceInterface(IContentProvider.descriptor); 176 Uri url = Uri.CREATOR.createFromParcel(data); 177 ContentValues values = ContentValues.CREATOR.createFromParcel(data); 178 String selection = data.readString(); 179 String[] selectionArgs = data.readStringArray(); 180 181 int count = update(url, values, selection, selectionArgs); 182 183 reply.writeNoException(); 184 reply.writeInt(count); 185 return true; 186 } 187 188 case OPEN_FILE_TRANSACTION: 189 { 190 data.enforceInterface(IContentProvider.descriptor); 191 Uri url = Uri.CREATOR.createFromParcel(data); 192 String mode = data.readString(); 193 194 ParcelFileDescriptor fd; 195 fd = openFile(url, mode); 196 reply.writeNoException(); 197 if (fd != null) { 198 reply.writeInt(1); 199 fd.writeToParcel(reply, 200 Parcelable.PARCELABLE_WRITE_RETURN_VALUE); 201 } else { 202 reply.writeInt(0); 203 } 204 return true; 205 } 206 207 case OPEN_ASSET_FILE_TRANSACTION: 208 { 209 data.enforceInterface(IContentProvider.descriptor); 210 Uri url = Uri.CREATOR.createFromParcel(data); 211 String mode = data.readString(); 212 213 AssetFileDescriptor fd; 214 fd = openAssetFile(url, mode); 215 reply.writeNoException(); 216 if (fd != null) { 217 reply.writeInt(1); 218 fd.writeToParcel(reply, 219 Parcelable.PARCELABLE_WRITE_RETURN_VALUE); 220 } else { 221 reply.writeInt(0); 222 } 223 return true; 224 } 225 } 226 } catch (Exception e) { 227 DatabaseUtils.writeExceptionToParcel(reply, e); 228 return true; 229 } 230 231 return super.onTransact(code, data, reply, flags); 232 } 233 234 public IBinder asBinder() 235 { 236 return this; 237 } 238} 239 240 241final class ContentProviderProxy implements IContentProvider 242{ 243 public ContentProviderProxy(IBinder remote) 244 { 245 mRemote = remote; 246 } 247 248 public IBinder asBinder() 249 { 250 return mRemote; 251 } 252 253 public IBulkCursor bulkQuery(Uri url, String[] projection, 254 String selection, String[] selectionArgs, String sortOrder, IContentObserver observer, 255 CursorWindow window) throws RemoteException { 256 Parcel data = Parcel.obtain(); 257 Parcel reply = Parcel.obtain(); 258 259 data.writeInterfaceToken(IContentProvider.descriptor); 260 261 url.writeToParcel(data, 0); 262 int length = 0; 263 if (projection != null) { 264 length = projection.length; 265 } 266 data.writeInt(length); 267 for (int i = 0; i < length; i++) { 268 data.writeString(projection[i]); 269 } 270 data.writeString(selection); 271 if (selectionArgs != null) { 272 length = selectionArgs.length; 273 } else { 274 length = 0; 275 } 276 data.writeInt(length); 277 for (int i = 0; i < length; i++) { 278 data.writeString(selectionArgs[i]); 279 } 280 data.writeString(sortOrder); 281 data.writeStrongBinder(observer.asBinder()); 282 window.writeToParcel(data, 0); 283 284 mRemote.transact(IContentProvider.QUERY_TRANSACTION, data, reply, 0); 285 286 DatabaseUtils.readExceptionFromParcel(reply); 287 288 IBulkCursor bulkCursor = null; 289 IBinder bulkCursorBinder = reply.readStrongBinder(); 290 if (bulkCursorBinder != null) { 291 bulkCursor = BulkCursorNative.asInterface(bulkCursorBinder); 292 } 293 294 data.recycle(); 295 reply.recycle(); 296 297 return bulkCursor; 298 } 299 300 public Cursor query(Uri url, String[] projection, String selection, 301 String[] selectionArgs, String sortOrder) throws RemoteException { 302 //TODO make a pool of windows so we can reuse memory dealers 303 CursorWindow window = new CursorWindow(false /* window will be used remotely */); 304 BulkCursorToCursorAdaptor adaptor = new BulkCursorToCursorAdaptor(); 305 IBulkCursor bulkCursor = bulkQuery(url, projection, selection, selectionArgs, sortOrder, 306 adaptor.getObserver(), window); 307 308 if (bulkCursor == null) { 309 return null; 310 } 311 adaptor.set(bulkCursor); 312 return adaptor; 313 } 314 315 public String getType(Uri url) throws RemoteException 316 { 317 Parcel data = Parcel.obtain(); 318 Parcel reply = Parcel.obtain(); 319 320 data.writeInterfaceToken(IContentProvider.descriptor); 321 322 url.writeToParcel(data, 0); 323 324 mRemote.transact(IContentProvider.GET_TYPE_TRANSACTION, data, reply, 0); 325 326 DatabaseUtils.readExceptionFromParcel(reply); 327 String out = reply.readString(); 328 329 data.recycle(); 330 reply.recycle(); 331 332 return out; 333 } 334 335 public Uri insert(Uri url, ContentValues values) throws RemoteException 336 { 337 Parcel data = Parcel.obtain(); 338 Parcel reply = Parcel.obtain(); 339 340 data.writeInterfaceToken(IContentProvider.descriptor); 341 342 url.writeToParcel(data, 0); 343 values.writeToParcel(data, 0); 344 345 mRemote.transact(IContentProvider.INSERT_TRANSACTION, data, reply, 0); 346 347 DatabaseUtils.readExceptionFromParcel(reply); 348 Uri out = Uri.CREATOR.createFromParcel(reply); 349 350 data.recycle(); 351 reply.recycle(); 352 353 return out; 354 } 355 356 public int bulkInsert(Uri url, ContentValues[] values) throws RemoteException { 357 Parcel data = Parcel.obtain(); 358 Parcel reply = Parcel.obtain(); 359 360 data.writeInterfaceToken(IContentProvider.descriptor); 361 362 url.writeToParcel(data, 0); 363 data.writeTypedArray(values, 0); 364 365 mRemote.transact(IContentProvider.BULK_INSERT_TRANSACTION, data, reply, 0); 366 367 DatabaseUtils.readExceptionFromParcel(reply); 368 int count = reply.readInt(); 369 370 data.recycle(); 371 reply.recycle(); 372 373 return count; 374 } 375 376 public ContentProviderResult[] applyBatch(ArrayList<ContentProviderOperation> operations) 377 throws RemoteException, OperationApplicationException { 378 Parcel data = Parcel.obtain(); 379 Parcel reply = Parcel.obtain(); 380 381 data.writeInterfaceToken(IContentProvider.descriptor); 382 data.writeInt(operations.size()); 383 for (ContentProviderOperation operation : operations) { 384 operation.writeToParcel(data, 0); 385 } 386 mRemote.transact(IContentProvider.APPLY_BATCH_TRANSACTION, data, reply, 0); 387 388 DatabaseUtils.readExceptionWithOperationApplicationExceptionFromParcel(reply); 389 final ContentProviderResult[] results = 390 reply.createTypedArray(ContentProviderResult.CREATOR); 391 392 data.recycle(); 393 reply.recycle(); 394 395 return results; 396 } 397 398 public int delete(Uri url, String selection, String[] selectionArgs) 399 throws RemoteException { 400 Parcel data = Parcel.obtain(); 401 Parcel reply = Parcel.obtain(); 402 403 data.writeInterfaceToken(IContentProvider.descriptor); 404 405 url.writeToParcel(data, 0); 406 data.writeString(selection); 407 data.writeStringArray(selectionArgs); 408 409 mRemote.transact(IContentProvider.DELETE_TRANSACTION, data, reply, 0); 410 411 DatabaseUtils.readExceptionFromParcel(reply); 412 int count = reply.readInt(); 413 414 data.recycle(); 415 reply.recycle(); 416 417 return count; 418 } 419 420 public int update(Uri url, ContentValues values, String selection, 421 String[] selectionArgs) throws RemoteException { 422 Parcel data = Parcel.obtain(); 423 Parcel reply = Parcel.obtain(); 424 425 data.writeInterfaceToken(IContentProvider.descriptor); 426 427 url.writeToParcel(data, 0); 428 values.writeToParcel(data, 0); 429 data.writeString(selection); 430 data.writeStringArray(selectionArgs); 431 432 mRemote.transact(IContentProvider.UPDATE_TRANSACTION, data, reply, 0); 433 434 DatabaseUtils.readExceptionFromParcel(reply); 435 int count = reply.readInt(); 436 437 data.recycle(); 438 reply.recycle(); 439 440 return count; 441 } 442 443 public ParcelFileDescriptor openFile(Uri url, String mode) 444 throws RemoteException, FileNotFoundException { 445 Parcel data = Parcel.obtain(); 446 Parcel reply = Parcel.obtain(); 447 448 data.writeInterfaceToken(IContentProvider.descriptor); 449 450 url.writeToParcel(data, 0); 451 data.writeString(mode); 452 453 mRemote.transact(IContentProvider.OPEN_FILE_TRANSACTION, data, reply, 0); 454 455 DatabaseUtils.readExceptionWithFileNotFoundExceptionFromParcel(reply); 456 int has = reply.readInt(); 457 ParcelFileDescriptor fd = has != 0 ? reply.readFileDescriptor() : null; 458 459 data.recycle(); 460 reply.recycle(); 461 462 return fd; 463 } 464 465 public AssetFileDescriptor openAssetFile(Uri url, String mode) 466 throws RemoteException, FileNotFoundException { 467 Parcel data = Parcel.obtain(); 468 Parcel reply = Parcel.obtain(); 469 470 data.writeInterfaceToken(IContentProvider.descriptor); 471 472 url.writeToParcel(data, 0); 473 data.writeString(mode); 474 475 mRemote.transact(IContentProvider.OPEN_ASSET_FILE_TRANSACTION, data, reply, 0); 476 477 DatabaseUtils.readExceptionWithFileNotFoundExceptionFromParcel(reply); 478 int has = reply.readInt(); 479 AssetFileDescriptor fd = has != 0 480 ? AssetFileDescriptor.CREATOR.createFromParcel(reply) : null; 481 482 data.recycle(); 483 reply.recycle(); 484 485 return fd; 486 } 487 488 private IBinder mRemote; 489} 490 491