Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit d01571e6 authored by Jeff Sharkey's avatar Jeff Sharkey
Browse files

Isolate calls to each remote DocumentsProvider.

All background work is going through AsyncTasks, which uses a shared
thread pool.  Even with the new ContentProviderClient logic to detect
ANRs, the UI can still appear to be unresponsive for 20 seconds, even
if the user attempted to switch to a different backend.  In the worst
case, a backlog of thumbnail requests would end up wedging Loaders
for a long time, since they all share the same THREAD_POOL_EXECUTOR.

This change isolates calls to each provider onto their own thread,
which they're free to wedge and recover from over time.

It also means we no longer need a dedicated thread pool for recents
loading, and can use a simpler Semaphore instead.

Disables thumbnails in recents on svelte devices.

Bug: 10993301, 11014856
Change-Id: I7f8a5bbb5f64437e006cb2c48b7e854136d5c38c
parent ee3e1603
Loading
Loading
Loading
Loading
+10 −1
Original line number Diff line number Diff line
@@ -26,6 +26,7 @@ import android.util.TimeUtils;
import java.io.FileDescriptor;
import java.io.PrintWriter;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.Executor;

/**
 * Abstract Loader that provides an {@link AsyncTask} to do the work.  See
@@ -123,6 +124,8 @@ public abstract class AsyncTaskLoader<D> extends Loader<D> {
        }
    }

    private final Executor mExecutor;

    volatile LoadTask mTask;
    volatile LoadTask mCancellingTask;

@@ -131,7 +134,13 @@ public abstract class AsyncTaskLoader<D> extends Loader<D> {
    Handler mHandler;

    public AsyncTaskLoader(Context context) {
        this(context, AsyncTask.THREAD_POOL_EXECUTOR);
    }

    /** {@hide} */
    public AsyncTaskLoader(Context context, Executor executor) {
        super(context);
        mExecutor = executor;
    }

    /**
@@ -223,7 +232,7 @@ public abstract class AsyncTaskLoader<D> extends Loader<D> {
                }
            }
            if (DEBUG) Slog.v(TAG, "Executing: " + mTask);
            mTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, (Void[]) null);
            mTask.executeOnExecutor(mExecutor, (Void[]) null);
        }
    }

+6 −1
Original line number Diff line number Diff line
@@ -69,7 +69,12 @@ public class CreateDirectoryFragment extends DialogFragment {
            @Override
            public void onClick(DialogInterface dialog, int which) {
                final String displayName = text1.getText().toString();
                new CreateDirectoryTask(displayName).execute();

                final DocumentsActivity activity = (DocumentsActivity) getActivity();
                final DocumentInfo cwd = activity.getCurrentDirectory();

                new CreateDirectoryTask(displayName).executeOnExecutor(
                        ProviderExecutor.forAuthority(cwd.authority));
            }
        });
        builder.setNegativeButton(android.R.string.cancel, null);
+30 −9
Original line number Diff line number Diff line
@@ -27,6 +27,7 @@ import static com.android.documentsui.model.DocumentInfo.getCursorInt;
import static com.android.documentsui.model.DocumentInfo.getCursorLong;
import static com.android.documentsui.model.DocumentInfo.getCursorString;

import android.app.ActivityManager;
import android.app.Fragment;
import android.app.FragmentManager;
import android.app.FragmentTransaction;
@@ -113,6 +114,7 @@ public class DirectoryFragment extends Fragment {

    private boolean mHideGridTitles = false;

    private boolean mSvelteRecents;
    private Point mThumbSize;

    private DocumentsAdapter mAdapter;
@@ -203,6 +205,19 @@ public class DirectoryFragment extends Fragment {
        return view;
    }

    @Override
    public void onDestroyView() {
        super.onDestroyView();

        // Cancel any outstanding thumbnail requests
        final ViewGroup target = (mListView.getAdapter() != null) ? mListView : mGridView;
        final int count = target.getChildCount();
        for (int i = 0; i < count; i++) {
            final View view = target.getChildAt(i);
            mRecycleListener.onMovedToScrapHeap(view);
        }
    }

    @Override
    public void onActivityCreated(Bundle savedInstanceState) {
        super.onActivityCreated(savedInstanceState);
@@ -225,6 +240,10 @@ public class DirectoryFragment extends Fragment {
            mHideGridTitles = (doc != null) && doc.isGridTitlesHidden();
        }

        final ActivityManager am = (ActivityManager) context.getSystemService(
                Context.ACTIVITY_SERVICE);
        mSvelteRecents = am.isLowRamDevice() && (mType == TYPE_RECENT_OPEN);

        mCallbacks = new LoaderCallbacks<DirectoryResult>() {
            @Override
            public Loader<DirectoryResult> onCreateLoader(int id, Bundle args) {
@@ -260,7 +279,7 @@ public class DirectoryFragment extends Fragment {
            public void onLoadFinished(Loader<DirectoryResult> loader, DirectoryResult result) {
                if (!isAdded()) return;

                mAdapter.swapResult(result.cursor, result.exception);
                mAdapter.swapResult(result);

                // Push latest state up to UI
                // TODO: if mode change was racing with us, don't overwrite it
@@ -286,7 +305,7 @@ public class DirectoryFragment extends Fragment {

            @Override
            public void onLoaderReset(Loader<DirectoryResult> loader) {
                mAdapter.swapResult(null, null);
                mAdapter.swapResult(null);
            }
        };

@@ -654,13 +673,13 @@ public class DirectoryFragment extends Fragment {

        private List<Footer> mFooters = Lists.newArrayList();

        public void swapResult(Cursor cursor, Exception e) {
            mCursor = cursor;
            mCursorCount = cursor != null ? cursor.getCount() : 0;
        public void swapResult(DirectoryResult result) {
            mCursor = result != null ? result.cursor : null;
            mCursorCount = mCursor != null ? mCursor.getCount() : 0;

            mFooters.clear();

            final Bundle extras = cursor != null ? cursor.getExtras() : null;
            final Bundle extras = mCursor != null ? mCursor.getExtras() : null;
            if (extras != null) {
                final String info = extras.getString(DocumentsContract.EXTRA_INFO);
                if (info != null) {
@@ -675,7 +694,7 @@ public class DirectoryFragment extends Fragment {
                }
            }

            if (e != null) {
            if (result != null && result.exception != null) {
                mFooters.add(new MessageFooter(
                        3, R.drawable.ic_dialog_alert, getString(R.string.query_error)));
            }
@@ -776,7 +795,7 @@ public class DirectoryFragment extends Fragment {
            final boolean supportsThumbnail = (docFlags & Document.FLAG_SUPPORTS_THUMBNAIL) != 0;
            final boolean allowThumbnail = (state.derivedMode == MODE_GRID)
                    || MimePredicate.mimeMatches(MimePredicate.VISUAL_MIMES, docMimeType);
            final boolean showThumbnail = supportsThumbnail && allowThumbnail;
            final boolean showThumbnail = supportsThumbnail && allowThumbnail && !mSvelteRecents;

            boolean cacheHit = false;
            if (showThumbnail) {
@@ -790,7 +809,7 @@ public class DirectoryFragment extends Fragment {
                    final ThumbnailAsyncTask task = new ThumbnailAsyncTask(
                            uri, iconMime, iconThumb, mThumbSize);
                    iconThumb.setTag(task);
                    task.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
                    task.executeOnExecutor(ProviderExecutor.forAuthority(docAuthority));
                }
            }

@@ -983,6 +1002,8 @@ public class DirectoryFragment extends Fragment {

        @Override
        protected Bitmap doInBackground(Uri... params) {
            if (isCancelled()) return null;

            final Context context = mIconThumb.getContext();
            final ContentResolver resolver = context.getContentResolver();

+6 −5
Original line number Diff line number Diff line
@@ -79,7 +79,7 @@ public class DirectoryLoader extends AsyncTaskLoader<DirectoryResult> {

    public DirectoryLoader(Context context, int type, RootInfo root, DocumentInfo doc, Uri uri,
            int userSortOrder) {
        super(context);
        super(context, ProviderExecutor.forAuthority(root.authority));
        mType = type;
        mRoot = root;
        mDoc = doc;
@@ -157,11 +157,11 @@ public class DirectoryLoader extends AsyncTaskLoader<DirectoryResult> {
        Log.d(TAG, "userMode=" + userMode + ", userSortOrder=" + mUserSortOrder + " --> mode="
                + result.mode + ", sortOrder=" + result.sortOrder);

        ContentProviderClient client = null;
        try {
            result.client = DocumentsApplication.acquireUnstableProviderOrThrow(
                    resolver, authority);
            client = DocumentsApplication.acquireUnstableProviderOrThrow(resolver, authority);

            cursor = result.client.query(
            cursor = client.query(
                    mUri, null, null, null, getQuerySortOrder(result.sortOrder), mSignal);
            cursor.registerContentObserver(mObserver);

@@ -175,11 +175,12 @@ public class DirectoryLoader extends AsyncTaskLoader<DirectoryResult> {
                cursor = new SortingCursorWrapper(cursor, result.sortOrder);
            }

            result.client = client;
            result.cursor = cursor;
        } catch (Exception e) {
            Log.w(TAG, "Failed to query", e);
            result.exception = e;
            ContentProviderClient.releaseQuietly(result.client);
            ContentProviderClient.releaseQuietly(client);
        } finally {
            synchronized (this) {
                mSignal = null;
+16 −6
Original line number Diff line number Diff line
@@ -91,6 +91,7 @@ import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.concurrent.Executor;

public class DocumentsActivity extends Activity {
    public static final String TAG = "Documents";
@@ -215,7 +216,7 @@ public class DocumentsActivity extends Activity {
        if (!mState.restored) {
            if (mState.action == ACTION_MANAGE) {
                final Uri rootUri = getIntent().getData();
                new RestoreRootTask(rootUri).execute();
                new RestoreRootTask(rootUri).executeOnExecutor(getCurrentExecutor());
            } else {
                new RestoreStackTask().execute();
            }
@@ -782,6 +783,15 @@ public class DocumentsActivity extends Activity {
        return mState.stack.peek();
    }

    public Executor getCurrentExecutor() {
        final DocumentInfo cwd = getCurrentDirectory();
        if (cwd != null && cwd.authority != null) {
            return ProviderExecutor.forAuthority(cwd.authority);
        } else {
            return AsyncTask.THREAD_POOL_EXECUTOR;
        }
    }

    public State getDisplayState() {
        return mState;
    }
@@ -855,7 +865,7 @@ public class DocumentsActivity extends Activity {
        mState.stackTouched = true;

        if (!mRoots.isRecentsRoot(root)) {
            new PickRootTask(root).execute();
            new PickRootTask(root).executeOnExecutor(getCurrentExecutor());
        } else {
            onCurrentDirectoryChanged(ANIM_SIDE);
        }
@@ -932,7 +942,7 @@ public class DocumentsActivity extends Activity {
            onCurrentDirectoryChanged(ANIM_DOWN);
        } else if (mState.action == ACTION_OPEN || mState.action == ACTION_GET_CONTENT) {
            // Explicit file picked, return
            new ExistingFinishTask(doc.derivedUri).execute();
            new ExistingFinishTask(doc.derivedUri).executeOnExecutor(getCurrentExecutor());
        } else if (mState.action == ACTION_CREATE) {
            // Replace selected file
            SaveFragment.get(fm).setReplaceTarget(doc);
@@ -966,16 +976,16 @@ public class DocumentsActivity extends Activity {
            for (int i = 0; i < size; i++) {
                uris[i] = docs.get(i).derivedUri;
            }
            new ExistingFinishTask(uris).execute();
            new ExistingFinishTask(uris).executeOnExecutor(getCurrentExecutor());
        }
    }

    public void onSaveRequested(DocumentInfo replaceTarget) {
        new ExistingFinishTask(replaceTarget.derivedUri).execute();
        new ExistingFinishTask(replaceTarget.derivedUri).executeOnExecutor(getCurrentExecutor());
    }

    public void onSaveRequested(String mimeType, String displayName) {
        new CreateFinishTask(mimeType, displayName).execute();
        new CreateFinishTask(mimeType, displayName).executeOnExecutor(getCurrentExecutor());
    }

    private void saveStackBlocking() {
Loading