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 17 package android.database; 18 19 import android.compat.annotation.UnsupportedAppUsage; 20 import android.os.Binder; 21 import android.os.Bundle; 22 import android.os.IBinder; 23 import android.os.Parcel; 24 import android.os.Parcelable; 25 import android.os.RemoteException; 26 27 /** 28 * Native implementation of the bulk cursor. This is only for use in implementing 29 * IPC, application code should use the Cursor interface. 30 * 31 * {@hide} 32 */ 33 public abstract class BulkCursorNative extends Binder implements IBulkCursor 34 { BulkCursorNative()35 public BulkCursorNative() 36 { 37 attachInterface(this, descriptor); 38 } 39 40 /** 41 * Cast a Binder object into a content resolver interface, generating 42 * a proxy if needed. 43 */ asInterface(IBinder obj)44 static public IBulkCursor asInterface(IBinder obj) 45 { 46 if (obj == null) { 47 return null; 48 } 49 IBulkCursor in = (IBulkCursor)obj.queryLocalInterface(descriptor); 50 if (in != null) { 51 return in; 52 } 53 54 return new BulkCursorProxy(obj); 55 } 56 57 @Override onTransact(int code, Parcel data, Parcel reply, int flags)58 public boolean onTransact(int code, Parcel data, Parcel reply, int flags) 59 throws RemoteException { 60 try { 61 switch (code) { 62 case GET_CURSOR_WINDOW_TRANSACTION: { 63 data.enforceInterface(IBulkCursor.descriptor); 64 int startPos = data.readInt(); 65 CursorWindow window = getWindow(startPos); 66 reply.writeNoException(); 67 if (window == null) { 68 reply.writeInt(0); 69 } else { 70 reply.writeInt(1); 71 window.writeToParcel(reply, Parcelable.PARCELABLE_WRITE_RETURN_VALUE); 72 } 73 return true; 74 } 75 76 case DEACTIVATE_TRANSACTION: { 77 data.enforceInterface(IBulkCursor.descriptor); 78 deactivate(); 79 reply.writeNoException(); 80 return true; 81 } 82 83 case CLOSE_TRANSACTION: { 84 data.enforceInterface(IBulkCursor.descriptor); 85 close(); 86 reply.writeNoException(); 87 return true; 88 } 89 90 case REQUERY_TRANSACTION: { 91 data.enforceInterface(IBulkCursor.descriptor); 92 IContentObserver observer = 93 IContentObserver.Stub.asInterface(data.readStrongBinder()); 94 int count = requery(observer); 95 reply.writeNoException(); 96 reply.writeInt(count); 97 reply.writeBundle(getExtras()); 98 return true; 99 } 100 101 case ON_MOVE_TRANSACTION: { 102 data.enforceInterface(IBulkCursor.descriptor); 103 int position = data.readInt(); 104 onMove(position); 105 reply.writeNoException(); 106 return true; 107 } 108 109 case GET_EXTRAS_TRANSACTION: { 110 data.enforceInterface(IBulkCursor.descriptor); 111 Bundle extras = getExtras(); 112 reply.writeNoException(); 113 reply.writeBundle(extras); 114 return true; 115 } 116 117 case RESPOND_TRANSACTION: { 118 data.enforceInterface(IBulkCursor.descriptor); 119 Bundle extras = data.readBundle(); 120 Bundle returnExtras = respond(extras); 121 reply.writeNoException(); 122 reply.writeBundle(returnExtras); 123 return true; 124 } 125 } 126 } catch (Exception e) { 127 DatabaseUtils.writeExceptionToParcel(reply, e); 128 return true; 129 } 130 131 return super.onTransact(code, data, reply, flags); 132 } 133 asBinder()134 public IBinder asBinder() 135 { 136 return this; 137 } 138 } 139 140 141 final class BulkCursorProxy implements IBulkCursor { 142 @UnsupportedAppUsage 143 private IBinder mRemote; 144 private Bundle mExtras; 145 BulkCursorProxy(IBinder remote)146 public BulkCursorProxy(IBinder remote) 147 { 148 mRemote = remote; 149 mExtras = null; 150 } 151 asBinder()152 public IBinder asBinder() 153 { 154 return mRemote; 155 } 156 getWindow(int position)157 public CursorWindow getWindow(int position) throws RemoteException 158 { 159 Parcel data = Parcel.obtain(); 160 Parcel reply = Parcel.obtain(); 161 try { 162 data.writeInterfaceToken(IBulkCursor.descriptor); 163 data.writeInt(position); 164 165 mRemote.transact(GET_CURSOR_WINDOW_TRANSACTION, data, reply, 0); 166 DatabaseUtils.readExceptionFromParcel(reply); 167 168 CursorWindow window = null; 169 if (reply.readInt() == 1) { 170 window = CursorWindow.newFromParcel(reply); 171 } 172 return window; 173 } finally { 174 data.recycle(); 175 reply.recycle(); 176 } 177 } 178 onMove(int position)179 public void onMove(int position) throws RemoteException { 180 Parcel data = Parcel.obtain(); 181 Parcel reply = Parcel.obtain(); 182 try { 183 data.writeInterfaceToken(IBulkCursor.descriptor); 184 data.writeInt(position); 185 186 mRemote.transact(ON_MOVE_TRANSACTION, data, reply, 0); 187 DatabaseUtils.readExceptionFromParcel(reply); 188 } finally { 189 data.recycle(); 190 reply.recycle(); 191 } 192 } 193 deactivate()194 public void deactivate() throws RemoteException 195 { 196 Parcel data = Parcel.obtain(); 197 Parcel reply = Parcel.obtain(); 198 try { 199 data.writeInterfaceToken(IBulkCursor.descriptor); 200 201 mRemote.transact(DEACTIVATE_TRANSACTION, data, reply, 0); 202 DatabaseUtils.readExceptionFromParcel(reply); 203 } finally { 204 data.recycle(); 205 reply.recycle(); 206 } 207 } 208 close()209 public void close() throws RemoteException 210 { 211 Parcel data = Parcel.obtain(); 212 Parcel reply = Parcel.obtain(); 213 try { 214 data.writeInterfaceToken(IBulkCursor.descriptor); 215 216 mRemote.transact(CLOSE_TRANSACTION, data, reply, 0); 217 DatabaseUtils.readExceptionFromParcel(reply); 218 } finally { 219 data.recycle(); 220 reply.recycle(); 221 } 222 } 223 requery(IContentObserver observer)224 public int requery(IContentObserver observer) throws RemoteException { 225 Parcel data = Parcel.obtain(); 226 Parcel reply = Parcel.obtain(); 227 try { 228 data.writeInterfaceToken(IBulkCursor.descriptor); 229 data.writeStrongInterface(observer); 230 231 boolean result = mRemote.transact(REQUERY_TRANSACTION, data, reply, 0); 232 DatabaseUtils.readExceptionFromParcel(reply); 233 234 int count; 235 if (!result) { 236 count = -1; 237 } else { 238 count = reply.readInt(); 239 mExtras = reply.readBundle(); 240 } 241 return count; 242 } finally { 243 data.recycle(); 244 reply.recycle(); 245 } 246 } 247 getExtras()248 public Bundle getExtras() throws RemoteException { 249 if (mExtras == null) { 250 Parcel data = Parcel.obtain(); 251 Parcel reply = Parcel.obtain(); 252 try { 253 data.writeInterfaceToken(IBulkCursor.descriptor); 254 255 mRemote.transact(GET_EXTRAS_TRANSACTION, data, reply, 0); 256 DatabaseUtils.readExceptionFromParcel(reply); 257 258 mExtras = reply.readBundle(); 259 } finally { 260 data.recycle(); 261 reply.recycle(); 262 } 263 } 264 return mExtras; 265 } 266 respond(Bundle extras)267 public Bundle respond(Bundle extras) throws RemoteException { 268 Parcel data = Parcel.obtain(); 269 Parcel reply = Parcel.obtain(); 270 try { 271 data.writeInterfaceToken(IBulkCursor.descriptor); 272 data.writeBundle(extras); 273 274 mRemote.transact(RESPOND_TRANSACTION, data, reply, 0); 275 DatabaseUtils.readExceptionFromParcel(reply); 276 277 Bundle returnExtras = reply.readBundle(); 278 return returnExtras; 279 } finally { 280 data.recycle(); 281 reply.recycle(); 282 } 283 } 284 } 285 286