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 // If close() is being called from the finalizer thread, do not wait for a reply from 216 // the remote side. 217 final boolean fromFinalizer = 218 android.database.sqlite.Flags.onewayFinalizerCloseFixed() 219 && "FinalizerDaemon".equals(Thread.currentThread().getName()); 220 mRemote.transact(CLOSE_TRANSACTION, data, reply, 221 fromFinalizer ? IBinder.FLAG_ONEWAY: 0); 222 if (!fromFinalizer) { 223 DatabaseUtils.readExceptionFromParcel(reply); 224 } 225 } finally { 226 data.recycle(); 227 reply.recycle(); 228 } 229 } 230 requery(IContentObserver observer)231 public int requery(IContentObserver observer) throws RemoteException { 232 Parcel data = Parcel.obtain(); 233 Parcel reply = Parcel.obtain(); 234 try { 235 data.writeInterfaceToken(IBulkCursor.descriptor); 236 data.writeStrongInterface(observer); 237 238 boolean result = mRemote.transact(REQUERY_TRANSACTION, data, reply, 0); 239 DatabaseUtils.readExceptionFromParcel(reply); 240 241 int count; 242 if (!result) { 243 count = -1; 244 } else { 245 count = reply.readInt(); 246 mExtras = reply.readBundle(); 247 } 248 return count; 249 } finally { 250 data.recycle(); 251 reply.recycle(); 252 } 253 } 254 getExtras()255 public Bundle getExtras() throws RemoteException { 256 if (mExtras == null) { 257 Parcel data = Parcel.obtain(); 258 Parcel reply = Parcel.obtain(); 259 try { 260 data.writeInterfaceToken(IBulkCursor.descriptor); 261 262 mRemote.transact(GET_EXTRAS_TRANSACTION, data, reply, 0); 263 DatabaseUtils.readExceptionFromParcel(reply); 264 265 mExtras = reply.readBundle(); 266 } finally { 267 data.recycle(); 268 reply.recycle(); 269 } 270 } 271 return mExtras; 272 } 273 respond(Bundle extras)274 public Bundle respond(Bundle extras) throws RemoteException { 275 Parcel data = Parcel.obtain(); 276 Parcel reply = Parcel.obtain(); 277 try { 278 data.writeInterfaceToken(IBulkCursor.descriptor); 279 data.writeBundle(extras); 280 281 mRemote.transact(RESPOND_TRANSACTION, data, reply, 0); 282 DatabaseUtils.readExceptionFromParcel(reply); 283 284 Bundle returnExtras = reply.readBundle(); 285 return returnExtras; 286 } finally { 287 data.recycle(); 288 reply.recycle(); 289 } 290 } 291 } 292