ContentProviderNative.java revision 54b6cfa9a9e5b861a9930af873580d6dc20f773c
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.database.BulkCursorNative; 20import android.database.BulkCursorToCursorAdaptor; 21import android.database.Cursor; 22import android.database.CursorWindow; 23import android.database.DatabaseUtils; 24import android.database.IBulkCursor; 25import android.database.IContentObserver; 26import android.net.Uri; 27import android.os.Binder; 28import android.os.RemoteException; 29import android.os.IBinder; 30import android.os.Parcel; 31import android.os.ParcelFileDescriptor; 32import android.os.Parcelable; 33 34import java.io.FileNotFoundException; 35 36/** 37 * {@hide} 38 */ 39abstract public class ContentProviderNative extends Binder implements IContentProvider { 40 private static final String TAG = "ContentProvider"; 41 42 public ContentProviderNative() 43 { 44 attachInterface(this, descriptor); 45 } 46 47 /** 48 * Cast a Binder object into a content resolver interface, generating 49 * a proxy if needed. 50 */ 51 static public IContentProvider asInterface(IBinder obj) 52 { 53 if (obj == null) { 54 return null; 55 } 56 IContentProvider in = 57 (IContentProvider)obj.queryLocalInterface(descriptor); 58 if (in != null) { 59 return in; 60 } 61 62 return new ContentProviderProxy(obj); 63 } 64 65 @Override 66 public boolean onTransact(int code, Parcel data, Parcel reply, int flags) 67 throws RemoteException { 68 try { 69 switch (code) { 70 case QUERY_TRANSACTION: 71 { 72 data.enforceInterface(IContentProvider.descriptor); 73 Uri url = Uri.CREATOR.createFromParcel(data); 74 int num = data.readInt(); 75 String[] projection = null; 76 if (num > 0) { 77 projection = new String[num]; 78 for (int i = 0; i < num; i++) { 79 projection[i] = data.readString(); 80 } 81 } 82 String selection = data.readString(); 83 num = data.readInt(); 84 String[] selectionArgs = null; 85 if (num > 0) { 86 selectionArgs = new String[num]; 87 for (int i = 0; i < num; i++) { 88 selectionArgs[i] = data.readString(); 89 } 90 } 91 String sortOrder = data.readString(); 92 IContentObserver observer = IContentObserver.Stub. 93 asInterface(data.readStrongBinder()); 94 CursorWindow window = CursorWindow.CREATOR.createFromParcel(data); 95 96 IBulkCursor bulkCursor = bulkQuery(url, projection, selection, 97 selectionArgs, sortOrder, observer, window); 98 reply.writeNoException(); 99 if (bulkCursor != null) { 100 reply.writeStrongBinder(bulkCursor.asBinder()); 101 } else { 102 reply.writeStrongBinder(null); 103 } 104 return true; 105 } 106 107 case GET_TYPE_TRANSACTION: 108 { 109 data.enforceInterface(IContentProvider.descriptor); 110 Uri url = Uri.CREATOR.createFromParcel(data); 111 String type = getType(url); 112 reply.writeNoException(); 113 reply.writeString(type); 114 115 return true; 116 } 117 118 case INSERT_TRANSACTION: 119 { 120 data.enforceInterface(IContentProvider.descriptor); 121 Uri url = Uri.CREATOR.createFromParcel(data); 122 ContentValues values = ContentValues.CREATOR.createFromParcel(data); 123 124 Uri out = insert(url, values); 125 reply.writeNoException(); 126 Uri.writeToParcel(reply, out); 127 return true; 128 } 129 130 case BULK_INSERT_TRANSACTION: 131 { 132 data.enforceInterface(IContentProvider.descriptor); 133 Uri url = Uri.CREATOR.createFromParcel(data); 134 ContentValues[] values = data.createTypedArray(ContentValues.CREATOR); 135 136 int count = bulkInsert(url, values); 137 reply.writeNoException(); 138 reply.writeInt(count); 139 return true; 140 } 141 142 case DELETE_TRANSACTION: 143 { 144 data.enforceInterface(IContentProvider.descriptor); 145 Uri url = Uri.CREATOR.createFromParcel(data); 146 String selection = data.readString(); 147 String[] selectionArgs = data.readStringArray(); 148 149 int count = delete(url, selection, selectionArgs); 150 151 reply.writeNoException(); 152 reply.writeInt(count); 153 return true; 154 } 155 156 case UPDATE_TRANSACTION: 157 { 158 data.enforceInterface(IContentProvider.descriptor); 159 Uri url = Uri.CREATOR.createFromParcel(data); 160 ContentValues values = ContentValues.CREATOR.createFromParcel(data); 161 String selection = data.readString(); 162 String[] selectionArgs = data.readStringArray(); 163 164 int count = update(url, values, selection, selectionArgs); 165 166 reply.writeNoException(); 167 reply.writeInt(count); 168 return true; 169 } 170 171 case OPEN_FILE_TRANSACTION: 172 { 173 data.enforceInterface(IContentProvider.descriptor); 174 Uri url = Uri.CREATOR.createFromParcel(data); 175 String mode = data.readString(); 176 177 ParcelFileDescriptor fd; 178 fd = openFile(url, mode); 179 reply.writeNoException(); 180 if (fd != null) { 181 reply.writeInt(1); 182 fd.writeToParcel(reply, 183 Parcelable.PARCELABLE_WRITE_RETURN_VALUE); 184 } else { 185 reply.writeInt(0); 186 } 187 return true; 188 } 189 190 case GET_SYNC_ADAPTER_TRANSACTION: 191 { 192 data.enforceInterface(IContentProvider.descriptor); 193 ISyncAdapter sa = getSyncAdapter(); 194 reply.writeNoException(); 195 reply.writeStrongBinder(sa != null ? sa.asBinder() : null); 196 return true; 197 } 198 } 199 } catch (Exception e) { 200 DatabaseUtils.writeExceptionToParcel(reply, e); 201 return true; 202 } 203 204 return super.onTransact(code, data, reply, flags); 205 } 206 207 public IBinder asBinder() 208 { 209 return this; 210 } 211} 212 213 214final class ContentProviderProxy implements IContentProvider 215{ 216 public ContentProviderProxy(IBinder remote) 217 { 218 mRemote = remote; 219 } 220 221 public IBinder asBinder() 222 { 223 return mRemote; 224 } 225 226 public IBulkCursor bulkQuery(Uri url, String[] projection, 227 String selection, String[] selectionArgs, String sortOrder, IContentObserver observer, 228 CursorWindow window) throws RemoteException { 229 Parcel data = Parcel.obtain(); 230 Parcel reply = Parcel.obtain(); 231 232 data.writeInterfaceToken(IContentProvider.descriptor); 233 234 url.writeToParcel(data, 0); 235 int length = 0; 236 if (projection != null) { 237 length = projection.length; 238 } 239 data.writeInt(length); 240 for (int i = 0; i < length; i++) { 241 data.writeString(projection[i]); 242 } 243 data.writeString(selection); 244 if (selectionArgs != null) { 245 length = selectionArgs.length; 246 } else { 247 length = 0; 248 } 249 data.writeInt(length); 250 for (int i = 0; i < length; i++) { 251 data.writeString(selectionArgs[i]); 252 } 253 data.writeString(sortOrder); 254 data.writeStrongBinder(observer.asBinder()); 255 window.writeToParcel(data, 0); 256 257 mRemote.transact(IContentProvider.QUERY_TRANSACTION, data, reply, 0); 258 259 DatabaseUtils.readExceptionFromParcel(reply); 260 261 IBulkCursor bulkCursor = null; 262 IBinder bulkCursorBinder = reply.readStrongBinder(); 263 if (bulkCursorBinder != null) { 264 bulkCursor = BulkCursorNative.asInterface(bulkCursorBinder); 265 } 266 267 data.recycle(); 268 reply.recycle(); 269 270 return bulkCursor; 271 } 272 273 public Cursor query(Uri url, String[] projection, String selection, 274 String[] selectionArgs, String sortOrder) throws RemoteException { 275 //TODO make a pool of windows so we can reuse memory dealers 276 CursorWindow window = new CursorWindow(false /* window will be used remotely */); 277 BulkCursorToCursorAdaptor adaptor = new BulkCursorToCursorAdaptor(); 278 IBulkCursor bulkCursor = bulkQuery(url, projection, selection, selectionArgs, sortOrder, 279 adaptor.getObserver(), window); 280 281 if (bulkCursor == null) { 282 return null; 283 } 284 adaptor.set(bulkCursor); 285 return adaptor; 286 } 287 288 public String getType(Uri url) throws RemoteException 289 { 290 Parcel data = Parcel.obtain(); 291 Parcel reply = Parcel.obtain(); 292 293 data.writeInterfaceToken(IContentProvider.descriptor); 294 295 url.writeToParcel(data, 0); 296 297 mRemote.transact(IContentProvider.GET_TYPE_TRANSACTION, data, reply, 0); 298 299 DatabaseUtils.readExceptionFromParcel(reply); 300 String out = reply.readString(); 301 302 data.recycle(); 303 reply.recycle(); 304 305 return out; 306 } 307 308 public Uri insert(Uri url, ContentValues values) throws RemoteException 309 { 310 Parcel data = Parcel.obtain(); 311 Parcel reply = Parcel.obtain(); 312 313 data.writeInterfaceToken(IContentProvider.descriptor); 314 315 url.writeToParcel(data, 0); 316 values.writeToParcel(data, 0); 317 318 mRemote.transact(IContentProvider.INSERT_TRANSACTION, data, reply, 0); 319 320 DatabaseUtils.readExceptionFromParcel(reply); 321 Uri out = Uri.CREATOR.createFromParcel(reply); 322 323 data.recycle(); 324 reply.recycle(); 325 326 return out; 327 } 328 329 public int bulkInsert(Uri url, ContentValues[] values) throws RemoteException { 330 Parcel data = Parcel.obtain(); 331 Parcel reply = Parcel.obtain(); 332 333 data.writeInterfaceToken(IContentProvider.descriptor); 334 335 url.writeToParcel(data, 0); 336 data.writeTypedArray(values, 0); 337 338 mRemote.transact(IContentProvider.BULK_INSERT_TRANSACTION, data, reply, 0); 339 340 DatabaseUtils.readExceptionFromParcel(reply); 341 int count = reply.readInt(); 342 343 data.recycle(); 344 reply.recycle(); 345 346 return count; 347 } 348 349 public int delete(Uri url, String selection, String[] selectionArgs) 350 throws RemoteException { 351 Parcel data = Parcel.obtain(); 352 Parcel reply = Parcel.obtain(); 353 354 data.writeInterfaceToken(IContentProvider.descriptor); 355 356 url.writeToParcel(data, 0); 357 data.writeString(selection); 358 data.writeStringArray(selectionArgs); 359 360 mRemote.transact(IContentProvider.DELETE_TRANSACTION, data, reply, 0); 361 362 DatabaseUtils.readExceptionFromParcel(reply); 363 int count = reply.readInt(); 364 365 data.recycle(); 366 reply.recycle(); 367 368 return count; 369 } 370 371 public int update(Uri url, ContentValues values, String selection, 372 String[] selectionArgs) 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 values.writeToParcel(data, 0); 380 data.writeString(selection); 381 data.writeStringArray(selectionArgs); 382 383 mRemote.transact(IContentProvider.UPDATE_TRANSACTION, data, reply, 0); 384 385 DatabaseUtils.readExceptionFromParcel(reply); 386 int count = reply.readInt(); 387 388 data.recycle(); 389 reply.recycle(); 390 391 return count; 392 } 393 394 public ParcelFileDescriptor openFile(Uri url, String mode) 395 throws RemoteException, FileNotFoundException { 396 Parcel data = Parcel.obtain(); 397 Parcel reply = Parcel.obtain(); 398 399 data.writeInterfaceToken(IContentProvider.descriptor); 400 401 url.writeToParcel(data, 0); 402 data.writeString(mode); 403 404 mRemote.transact(IContentProvider.OPEN_FILE_TRANSACTION, data, reply, 0); 405 406 DatabaseUtils.readExceptionWithFileNotFoundExceptionFromParcel(reply); 407 int has = reply.readInt(); 408 ParcelFileDescriptor fd = has != 0 ? reply.readFileDescriptor() : null; 409 410 data.recycle(); 411 reply.recycle(); 412 413 return fd; 414 } 415 416 public ISyncAdapter getSyncAdapter() throws RemoteException { 417 Parcel data = Parcel.obtain(); 418 Parcel reply = Parcel.obtain(); 419 420 data.writeInterfaceToken(IContentProvider.descriptor); 421 422 mRemote.transact(IContentProvider.GET_SYNC_ADAPTER_TRANSACTION, data, reply, 0); 423 424 DatabaseUtils.readExceptionFromParcel(reply); 425 ISyncAdapter syncAdapter = ISyncAdapter.Stub.asInterface(reply.readStrongBinder()); 426 427 data.recycle(); 428 reply.recycle(); 429 430 return syncAdapter; 431 } 432 433 private IBinder mRemote; 434} 435 436