blob: 02eddf239dca4247c354d1d298aff93c79340972 [file] [log] [blame]
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001/*
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.database;
18
Jeff Brown655e66b2012-01-23 15:51:41 -080019import android.net.Uri;
Svetoslav86b1df22014-08-21 14:22:53 -070020import android.os.*;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080021
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080022
23/**
24 * Wraps a BulkCursor around an existing Cursor making it remotable.
Jeff Brownd2183652011-10-09 12:39:53 -070025 * <p>
Jeff Brownb4009c72011-10-12 16:05:41 -070026 * If the wrapped cursor returns non-null from {@link CrossProcessCursor#getWindow}
27 * then it is assumed to own the window. Otherwise, the adaptor provides a
28 * window to be filled and ensures it gets closed as needed during deactivation
Jeff Brownd2183652011-10-09 12:39:53 -070029 * and requeries.
30 * </p>
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080031 *
32 * {@hide}
33 */
Svetoslav86b1df22014-08-21 14:22:53 -070034public final class CursorToBulkCursorAdaptor extends BulkCursorNative
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080035 implements IBinder.DeathRecipient {
36 private static final String TAG = "Cursor";
Jeff Brownd2183652011-10-09 12:39:53 -070037
38 private final Object mLock = new Object();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080039 private final String mProviderName;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080040 private ContentObserverProxy mObserver;
41
Jeff Brownd2183652011-10-09 12:39:53 -070042 /**
43 * The cursor that is being adapted.
44 * This field is set to null when the cursor is closed.
45 */
46 private CrossProcessCursor mCursor;
47
48 /**
Jeff Brownb4009c72011-10-12 16:05:41 -070049 * The cursor window that was filled by the cross process cursor in the
50 * case where the cursor does not support getWindow.
51 * This field is only ever non-null when the window has actually be filled.
Jeff Brownd2183652011-10-09 12:39:53 -070052 */
Jeff Brownb4009c72011-10-12 16:05:41 -070053 private CursorWindow mFilledWindow;
Jeff Brownd2183652011-10-09 12:39:53 -070054
55 private static final class ContentObserverProxy extends ContentObserver {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080056 protected IContentObserver mRemote;
57
58 public ContentObserverProxy(IContentObserver remoteObserver, DeathRecipient recipient) {
59 super(null);
60 mRemote = remoteObserver;
61 try {
62 remoteObserver.asBinder().linkToDeath(recipient, 0);
63 } catch (RemoteException e) {
64 // Do nothing, the far side is dead
65 }
66 }
Svetoslav86b1df22014-08-21 14:22:53 -070067
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080068 public boolean unlinkToDeath(DeathRecipient recipient) {
69 return mRemote.asBinder().unlinkToDeath(recipient, 0);
70 }
71
72 @Override
73 public boolean deliverSelfNotifications() {
74 // The far side handles the self notifications.
75 return false;
76 }
77
78 @Override
Jeff Brown655e66b2012-01-23 15:51:41 -080079 public void onChange(boolean selfChange, Uri uri) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080080 try {
Svetoslav86b1df22014-08-21 14:22:53 -070081 mRemote.onChange(selfChange, uri, android.os.Process.myUid());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080082 } catch (RemoteException ex) {
83 // Do nothing, the far side is dead
84 }
85 }
86 }
87
Jeff Brown0cde89f2011-10-10 14:50:10 -070088 public CursorToBulkCursorAdaptor(Cursor cursor, IContentObserver observer,
89 String providerName) {
Jeff Brown825c5132011-10-12 16:11:30 -070090 if (cursor instanceof CrossProcessCursor) {
91 mCursor = (CrossProcessCursor)cursor;
92 } else {
93 mCursor = new CrossProcessCursorWrapper(cursor);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080094 }
95 mProviderName = providerName;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080096
Jeff Brownd2183652011-10-09 12:39:53 -070097 synchronized (mLock) {
98 createAndRegisterObserverProxyLocked(observer);
99 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800100 }
Jeff Brownd2183652011-10-09 12:39:53 -0700101
Jeff Brownb4009c72011-10-12 16:05:41 -0700102 private void closeFilledWindowLocked() {
103 if (mFilledWindow != null) {
104 mFilledWindow.close();
105 mFilledWindow = null;
Jeff Brown0cde89f2011-10-10 14:50:10 -0700106 }
107 }
108
109 private void disposeLocked() {
Jeff Brownd2183652011-10-09 12:39:53 -0700110 if (mCursor != null) {
111 unregisterObserverProxyLocked();
112 mCursor.close();
113 mCursor = null;
114 }
115
Jeff Brownb4009c72011-10-12 16:05:41 -0700116 closeFilledWindowLocked();
Jeff Brownd2183652011-10-09 12:39:53 -0700117 }
118
119 private void throwIfCursorIsClosed() {
120 if (mCursor == null) {
121 throw new StaleDataException("Attempted to access a cursor after it has been closed.");
122 }
123 }
124
125 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800126 public void binderDied() {
Jeff Brownd2183652011-10-09 12:39:53 -0700127 synchronized (mLock) {
Jeff Brown0cde89f2011-10-10 14:50:10 -0700128 disposeLocked();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800129 }
130 }
Jeff Brownd2183652011-10-09 12:39:53 -0700131
Jeff Brownc21b5a02013-01-07 17:15:12 -0800132 /**
133 * Returns an object that contains sufficient metadata to reconstruct
134 * the cursor remotely. May throw if an error occurs when executing the query
135 * and obtaining the row count.
136 */
Jeff Brownfb5a4962012-03-14 17:38:59 -0700137 public BulkCursorDescriptor getBulkCursorDescriptor() {
138 synchronized (mLock) {
139 throwIfCursorIsClosed();
140
141 BulkCursorDescriptor d = new BulkCursorDescriptor();
142 d.cursor = this;
143 d.columnNames = mCursor.getColumnNames();
144 d.wantsAllOnMoveCalls = mCursor.getWantsAllOnMoveCalls();
145 d.count = mCursor.getCount();
146 d.window = mCursor.getWindow();
147 if (d.window != null) {
148 // Acquire a reference to the window because its reference count will be
149 // decremented when it is returned as part of the binder call reply parcel.
150 d.window.acquireReference();
151 }
152 return d;
153 }
154 }
155
Jeff Brownd2183652011-10-09 12:39:53 -0700156 @Override
Jeff Brown650de3d2011-10-27 14:52:28 -0700157 public CursorWindow getWindow(int position) {
Jeff Brownd2183652011-10-09 12:39:53 -0700158 synchronized (mLock) {
159 throwIfCursorIsClosed();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800160
Jeff Brown650de3d2011-10-27 14:52:28 -0700161 if (!mCursor.moveToPosition(position)) {
Jeff Brownb4009c72011-10-12 16:05:41 -0700162 closeFilledWindowLocked();
163 return null;
164 }
Jeff Brown0cde89f2011-10-10 14:50:10 -0700165
Jeff Brownb4009c72011-10-12 16:05:41 -0700166 CursorWindow window = mCursor.getWindow();
167 if (window != null) {
168 closeFilledWindowLocked();
Jeff Brownd2183652011-10-09 12:39:53 -0700169 } else {
Jeff Brownb4009c72011-10-12 16:05:41 -0700170 window = mFilledWindow;
Jeff Brown0cde89f2011-10-10 14:50:10 -0700171 if (window == null) {
Jeff Brownb4009c72011-10-12 16:05:41 -0700172 mFilledWindow = new CursorWindow(mProviderName);
173 window = mFilledWindow;
Jeff Brown650de3d2011-10-27 14:52:28 -0700174 } else if (position < window.getStartPosition()
175 || position >= window.getStartPosition() + window.getNumRows()) {
Jeff Brownb4009c72011-10-12 16:05:41 -0700176 window.clear();
Jeff Brownd2183652011-10-09 12:39:53 -0700177 }
Jeff Brown650de3d2011-10-27 14:52:28 -0700178 mCursor.fillWindow(position, window);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800179 }
Jeff Brownd2183652011-10-09 12:39:53 -0700180
Jeff Brownd2183652011-10-09 12:39:53 -0700181 if (window != null) {
Jeff Brownfb5a4962012-03-14 17:38:59 -0700182 // Acquire a reference to the window because its reference count will be
183 // decremented when it is returned as part of the binder call reply parcel.
Jeff Brownd2183652011-10-09 12:39:53 -0700184 window.acquireReference();
185 }
186 return window;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800187 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800188 }
189
Jeff Brownd2183652011-10-09 12:39:53 -0700190 @Override
191 public void onMove(int position) {
192 synchronized (mLock) {
193 throwIfCursorIsClosed();
194
195 mCursor.onMove(mCursor.getPosition(), position);
196 }
197 }
198
199 @Override
Jeff Brownd2183652011-10-09 12:39:53 -0700200 public void deactivate() {
201 synchronized (mLock) {
202 if (mCursor != null) {
203 unregisterObserverProxyLocked();
204 mCursor.deactivate();
205 }
Jeff Brown0cde89f2011-10-10 14:50:10 -0700206
Jeff Brownb4009c72011-10-12 16:05:41 -0700207 closeFilledWindowLocked();
Jeff Brownd2183652011-10-09 12:39:53 -0700208 }
209 }
210
211 @Override
212 public void close() {
213 synchronized (mLock) {
Jeff Brown0cde89f2011-10-10 14:50:10 -0700214 disposeLocked();
Jeff Brownd2183652011-10-09 12:39:53 -0700215 }
216 }
217
218 @Override
Jeff Brown0cde89f2011-10-10 14:50:10 -0700219 public int requery(IContentObserver observer) {
Jeff Brownd2183652011-10-09 12:39:53 -0700220 synchronized (mLock) {
221 throwIfCursorIsClosed();
222
Jeff Brownb4009c72011-10-12 16:05:41 -0700223 closeFilledWindowLocked();
Jeff Brownd2183652011-10-09 12:39:53 -0700224
225 try {
226 if (!mCursor.requery()) {
227 return -1;
228 }
229 } catch (IllegalStateException e) {
230 IllegalStateException leakProgram = new IllegalStateException(
231 mProviderName + " Requery misuse db, mCursor isClosed:" +
232 mCursor.isClosed(), e);
233 throw leakProgram;
234 }
235
Jeff Brownd2183652011-10-09 12:39:53 -0700236 unregisterObserverProxyLocked();
237 createAndRegisterObserverProxyLocked(observer);
238 return mCursor.getCount();
239 }
240 }
241
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800242 /**
243 * Create a ContentObserver from the observer and register it as an observer on the
244 * underlying cursor.
245 * @param observer the IContentObserver that wants to monitor the cursor
246 * @throws IllegalStateException if an observer is already registered
247 */
Jeff Brownd2183652011-10-09 12:39:53 -0700248 private void createAndRegisterObserverProxyLocked(IContentObserver observer) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800249 if (mObserver != null) {
250 throw new IllegalStateException("an observer is already registered");
251 }
252 mObserver = new ContentObserverProxy(observer, this);
253 mCursor.registerContentObserver(mObserver);
254 }
255
256 /** Unregister the observer if it is already registered. */
Jeff Brownd2183652011-10-09 12:39:53 -0700257 private void unregisterObserverProxyLocked() {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800258 if (mObserver != null) {
259 mCursor.unregisterContentObserver(mObserver);
260 mObserver.unlinkToDeath(this);
261 mObserver = null;
262 }
263 }
264
Jeff Brownd2183652011-10-09 12:39:53 -0700265 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800266 public Bundle getExtras() {
Jeff Brownd2183652011-10-09 12:39:53 -0700267 synchronized (mLock) {
268 throwIfCursorIsClosed();
269
270 return mCursor.getExtras();
271 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800272 }
273
Jeff Brownd2183652011-10-09 12:39:53 -0700274 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800275 public Bundle respond(Bundle extras) {
Jeff Brownd2183652011-10-09 12:39:53 -0700276 synchronized (mLock) {
277 throwIfCursorIsClosed();
278
279 return mCursor.respond(extras);
280 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800281 }
282}