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

Commit ab0b3f67 authored by Matthew Fritze's avatar Matthew Fritze
Browse files

Prevent race conditions after dropping database

Block all loaders from accessing the database
before indexing is complete.

Bug: 37501479
Test: make RunSettingsRoboTests
Change-Id: I2af98dcf6bceacbeffa70bd40879c97bb0cbc828
Merged-In: I02f8423c0ffc27abbb8ceb61a8c47d2f0796d0bb
parent 4f5b13f9
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -79,7 +79,7 @@ public class SettingsActivity extends SettingsDrawerActivity

    private static final String LOG_TAG = "Settings";

    private static final int LOADER_ID_INDEXABLE_CONTENT_MONITOR = 1;
    public static final int LOADER_ID_INDEXABLE_CONTENT_MONITOR = 1;

    // Constants for state save/restore
    private static final String SAVE_KEY_CATEGORIES = ":settings:categories";
+12 −0
Original line number Diff line number Diff line
package com.android.settings.search;

/**
 * Callback for Settings search indexing.
 */
public interface IndexingCallback {

    /**
     * Called when Indexing is finished.
     */
    void onIndexingFinished();
}
+52 −19
Original line number Diff line number Diff line
@@ -42,6 +42,7 @@ import android.util.Xml;
import com.android.settings.core.PreferenceController;
import com.android.settings.search.IndexDatabaseHelper;
import com.android.settings.search.Indexable;
import com.android.settings.search.IndexingCallback;
import com.android.settings.search.SearchIndexableRaw;
import com.android.settings.search.SearchIndexableResources;

@@ -132,7 +133,8 @@ public class DatabaseIndexingManager {

    private final String mBaseAuthority;

    private final AtomicBoolean mIsAvailable = new AtomicBoolean(false);
    @VisibleForTesting
    final AtomicBoolean mIsIndexingComplete = new AtomicBoolean(false);

    @VisibleForTesting
    final UpdateData mDataToProcess = new UpdateData();
@@ -147,17 +149,13 @@ public class DatabaseIndexingManager {
        mContext = context;
    }

    public boolean isAvailable() {
        return mIsAvailable.get();
    public boolean isIndexingComplete() {
        return mIsIndexingComplete.get();
    }

    public void indexDatabase() {
        AsyncTask.execute(new Runnable() {
            @Override
            public void run() {
                performIndexing();
            }
        });
    public void indexDatabase(IndexingCallback callback) {
        IndexingTask task = new IndexingTask(callback);
        task.execute();
    }

    /**
@@ -171,15 +169,12 @@ public class DatabaseIndexingManager {
        final List<ResolveInfo> list =
                mContext.getPackageManager().queryIntentContentProviders(intent, 0);

        final String localeStr = Locale.getDefault().toString();
        final String fingerprint = Build.FINGERPRINT;
        String localeStr = Locale.getDefault().toString();
        String fingerprint = Build.FINGERPRINT;
        final boolean isFullIndex = isFullIndex(localeStr, fingerprint);

        // Drop the database when the locale or build has changed. This eliminates rows which are
        // dynamically inserted in the old language, or deprecated settings.
        if (isFullIndex) {
            final SQLiteDatabase db = getWritableDatabase();
            IndexDatabaseHelper.getInstance(mContext).reconstruct(db);
            rebuildDatabase();
        }

        for (final ResolveInfo info : list) {
@@ -217,6 +212,18 @@ public class DatabaseIndexingManager {
        return !isLocaleIndexed || !isBuildIndexed;
    }

    /**
     * Reconstruct the database in the following cases:
     * - Language has changed
     * - Build has changed
     */
    private void rebuildDatabase() {
        // Drop the database when the locale or build has changed. This eliminates rows which are
        // dynamically inserted in the old language, or deprecated settings.
        final SQLiteDatabase db = getWritableDatabase();
        IndexDatabaseHelper.getInstance(mContext).reconstruct(db);
    }

    /**
     * Adds new data to the database and verifies the correctness of the ENABLED column.
     * First, the data to be updated and all non-indexable keys are copied locally.
@@ -229,7 +236,6 @@ public class DatabaseIndexingManager {
     */
    @VisibleForTesting
    void updateDatabase(boolean needsReindexing, String localeStr) {
        mIsAvailable.set(false);
        final UpdateData copy;

        synchronized (mDataToProcess) {
@@ -264,8 +270,6 @@ public class DatabaseIndexingManager {
        } finally {
            database.endTransaction();
        }

        mIsAvailable.set(true);
    }

    /**
@@ -1223,4 +1227,33 @@ public class DatabaseIndexingManager {
            }
        }
    }

    public class IndexingTask extends AsyncTask<Void, Void, Void> {

        @VisibleForTesting
        IndexingCallback mCallback;

        public IndexingTask(IndexingCallback callback) {
            mCallback = callback;
        }

        @Override
        protected void onPreExecute() {
            mIsIndexingComplete.set(false);
        }

        @Override
        protected Void doInBackground(Void... voids) {
            performIndexing();
            return null;
        }

        @Override
        protected void onPostExecute(Void aVoid) {
            mIsIndexingComplete.set(true);
            if (mCallback != null) {
                mCallback.onIndexingFinished();
            }
        }
    }
}
 No newline at end of file
+7 −1
Original line number Diff line number Diff line
@@ -21,6 +21,7 @@ import android.view.Menu;

import android.view.View;
import com.android.settings.dashboard.SiteMapManager;
import com.android.settings.search.IndexingCallback;

/**
 * FeatureProvider for Settings Search
@@ -68,7 +69,12 @@ public interface SearchFeatureProvider {
    /**
     * Updates the Settings indexes
     */
    void updateIndex(Context context);
    void updateIndex(Context context, IndexingCallback callback);

    /**
     * @returns true when indexing is complete.
     */
    boolean isIndexingComplete(Context context);

    /**
     * Initializes the feedback button in case it was dismissed.
+11 −2
Original line number Diff line number Diff line
@@ -19,6 +19,7 @@ package com.android.settings.search2;
import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.support.annotation.VisibleForTesting;
import android.util.Log;
import android.view.Menu;
import android.view.MenuItem;
@@ -26,6 +27,9 @@ import android.view.MenuItem;
import com.android.settings.R;
import com.android.settings.applications.PackageManagerWrapperImpl;
import com.android.settings.dashboard.SiteMapManager;
import com.android.settings.search.IndexingCallback;

import java.util.concurrent.atomic.AtomicBoolean;

/**
 * FeatureProvider for the refactored search code.
@@ -88,6 +92,11 @@ public class SearchFeatureProviderImpl implements SearchFeatureProvider {
        return mDatabaseIndexingManager;
    }

    @Override
    public boolean isIndexingComplete(Context context) {
        return getIndexingManager(context).isIndexingComplete();
    }

    public SiteMapManager getSiteMapManager() {
        if (mSiteMapManager == null) {
            mSiteMapManager = new SiteMapManager();
@@ -96,9 +105,9 @@ public class SearchFeatureProviderImpl implements SearchFeatureProvider {
    }

    @Override
    public void updateIndex(Context context) {
    public void updateIndex(Context context, IndexingCallback callback) {
        long indexStartTime = System.currentTimeMillis();
        getIndexingManager(context).indexDatabase();
        getIndexingManager(context).indexDatabase(callback);
        Log.d(TAG, "IndexDatabase() took " +
                (System.currentTimeMillis() - indexStartTime) + " ms");
    }
Loading