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