• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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