| /* |
| * Copyright (C) 2011 The Android Open Source Project |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License |
| */ |
| |
| package com.android.providers.media; |
| |
| import android.content.BroadcastReceiver; |
| import android.content.Context; |
| import android.content.Intent; |
| import android.content.SharedPreferences; |
| import android.provider.Column; |
| import android.provider.ExportedSince; |
| import android.util.Log; |
| |
| import com.android.providers.media.util.ForegroundThread; |
| import com.android.providers.media.util.Metrics; |
| |
| import java.io.File; |
| |
| /** |
| * This will be launched during system boot, after the core system has |
| * been brought up but before any non-persistent processes have been |
| * started. It is launched in a special state, with no content provider |
| * or custom application class associated with the process running. |
| * |
| * It's job is to prime the contacts database. Either create it |
| * if it doesn't exist, or open it and force any necessary upgrades. |
| * All of this heavy lifting happens before the boot animation ends. |
| */ |
| public class MediaUpgradeReceiver extends BroadcastReceiver { |
| static final String TAG = "MediaUpgradeReceiver"; |
| static final String PREF_DB_VERSION = "db_version"; |
| |
| @Override |
| public void onReceive(Context context, Intent intent) { |
| // We are now running with the system up, but no apps started, |
| // so can do whatever cleanup after an upgrade that we want. |
| ForegroundThread.getExecutor().execute(() -> { |
| // Run database migration on a separate thread so that main thread |
| // is available for handling other MediaService requests. |
| tryMigratingDatabases(context); |
| }); |
| } |
| |
| private void tryMigratingDatabases(Context context) { |
| // Lookup the last known database version |
| SharedPreferences prefs = context.getSharedPreferences(TAG, Context.MODE_PRIVATE); |
| int prefVersion = prefs.getInt(PREF_DB_VERSION, 0); |
| int dbVersion = DatabaseHelper.getDatabaseVersion(context); |
| if (prefVersion == dbVersion) { |
| return; |
| } |
| prefs.edit().putInt(PREF_DB_VERSION, dbVersion).commit(); |
| |
| try { |
| File dbDir = context.getDatabasePath("foo").getParentFile(); |
| String[] files = dbDir.list(); |
| if (files == null) return; |
| for (int i=0; i<files.length; i++) { |
| String file = files[i]; |
| if (MediaProvider.isMediaDatabaseName(file)) { |
| long startTime = System.currentTimeMillis(); |
| Log.i(TAG, "---> Start upgrade of media database " + file); |
| try { |
| DatabaseHelper helper = new DatabaseHelper(context, file, false, false, |
| Column.class, ExportedSince.class, Metrics::logSchemaChange, null, |
| MediaProvider.MIGRATION_LISTENER, null); |
| helper.runWithTransaction((db) -> { |
| // Perform just enough to force database upgrade |
| return db.getVersion(); |
| }); |
| helper.close(); |
| } catch (Throwable t) { |
| Log.wtf(TAG, "Error during upgrade of media db " + file, t); |
| } finally { |
| } |
| Log.i(TAG, "<--- Finished upgrade of media database " + file |
| + " in " + (System.currentTimeMillis()-startTime) + "ms"); |
| } |
| } |
| } catch (Throwable t) { |
| // Something has gone terribly wrong. |
| Log.wtf(TAG, "Error during upgrade attempt.", t); |
| } |
| } |
| } |