@Override public Cursor query( final Uri uri, final String[] projection, final String selection, final String[] selectionArgs, final String sortOrder) { if (K9.app == null) { return null; } if (K9.DEBUG) { Log.v(K9.LOG_TAG, "MessageProvider/query: " + uri); } final Cursor cursor; final int code = mUriMatcher.match(uri); if (code == -1) { throw new IllegalStateException("Unrecognized URI: " + uri); } try { // since we used the list index as the UriMatcher code, using it // back to retrieve the handler from the list final QueryHandler handler = mQueryHandlers.get(code); cursor = handler.query(uri, projection, selection, selectionArgs, sortOrder); } catch (Exception e) { Log.e(K9.LOG_TAG, "Unable to execute query for URI: " + uri, e); return null; } return cursor; }
@Override public Cursor query( Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) throws Exception { mSemaphore.acquire(); final Cursor cursor; cursor = mDelegate.query(uri, projection, selection, selectionArgs, sortOrder); /* Android content resolvers can only process CrossProcessCursor instances */ if (!(cursor instanceof CrossProcessCursor)) { Log.w(K9.LOG_TAG, "Unsupported cursor, returning null: " + cursor); return null; } final MonitoredCursor wrapped = new MonitoredCursor((CrossProcessCursor) cursor, mSemaphore); /* use a weak reference not to actively prevent garbage collection */ final WeakReference<MonitoredCursor> weakReference = new WeakReference<MonitoredCursor>(wrapped); /* make sure the cursor is closed after 30 seconds */ mScheduledPool.schedule( new Runnable() { @Override public void run() { final MonitoredCursor monitored = weakReference.get(); if (monitored != null && !monitored.isClosed()) { Log.w(K9.LOG_TAG, "Forcibly closing remotely exposed cursor"); try { monitored.close(); } catch (Exception e) { Log.w(K9.LOG_TAG, "Exception while forcibly closing cursor", e); } } } }, 30, TimeUnit.SECONDS); return wrapped; }