1 /* <lambda>null2 * Copyright 2019 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 package androidx.work.impl 17 18 import android.content.Context 19 import android.os.Build 20 import androidx.annotation.RequiresApi 21 import androidx.annotation.RestrictTo 22 import androidx.work.Logger 23 import java.io.File 24 25 private val TAG = Logger.tagWithPrefix("WrkDbPathHelper") 26 27 /** @return The name of the database. */ 28 internal const val WORK_DATABASE_NAME = "androidx.work.workdb" 29 30 // Supporting files for a SQLite database 31 private val DATABASE_EXTRA_FILES = arrayOf("-journal", "-shm", "-wal") 32 33 /** Keeps track of {@link WorkDatabase} paths. */ 34 @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP) 35 object WorkDatabasePathHelper { 36 /** 37 * Migrates [WorkDatabase] to the no-backup directory. 38 * 39 * @param context The application context. 40 */ 41 @JvmStatic 42 fun migrateDatabase(context: Context) { 43 val defaultDatabasePath = getDefaultDatabasePath(context) 44 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && defaultDatabasePath.exists()) { 45 Logger.get().debug(TAG, "Migrating WorkDatabase to the no-backup directory") 46 migrationPaths(context).forEach { (source, destination) -> 47 if (source.exists()) { 48 if (destination.exists()) { 49 Logger.get().warning(TAG, "Over-writing contents of $destination") 50 } 51 val renamed = source.renameTo(destination) 52 val message = 53 if (renamed) { 54 "Migrated ${source}to $destination" 55 } else { 56 "Renaming $source to $destination failed" 57 } 58 Logger.get().debug(TAG, message) 59 } 60 } 61 } 62 } 63 64 /** 65 * Returns a [Map] of all paths which need to be migrated to the no-backup directory. 66 * 67 * @param context The application [Context] 68 * @return a [Map] of paths to be migrated from source -> destination 69 */ 70 fun migrationPaths(context: Context): Map<File, File> { 71 return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { 72 val databasePath = getDefaultDatabasePath(context) 73 val migratedPath = getDatabasePath(context) 74 val map = 75 DATABASE_EXTRA_FILES.associate { extra -> 76 File(databasePath.path + extra) to File(migratedPath.path + extra) 77 } 78 map + (databasePath to migratedPath) 79 } else emptyMap() 80 } 81 82 /** 83 * @param context The application [Context] 84 * @return The database path before migration to the no-backup directory. 85 */ 86 fun getDefaultDatabasePath(context: Context): File { 87 return context.getDatabasePath(WORK_DATABASE_NAME) 88 } 89 90 /** 91 * @param context The application [Context] 92 * @return The the migrated database path. 93 */ 94 fun getDatabasePath(context: Context): File { 95 return if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) { 96 // No notion of a backup directory exists. 97 getDefaultDatabasePath(context) 98 } else { 99 getNoBackupPath(context) 100 } 101 } 102 103 /** 104 * Return the path for a [File] path in the [Context.getNoBackupFilesDir] identified by the 105 * [String] fragment. 106 * 107 * @param context The application [Context] 108 * @return the [File] 109 */ 110 @RequiresApi(23) 111 private fun getNoBackupPath(context: Context): File { 112 return File(Api21Impl.getNoBackupFilesDir(context), WORK_DATABASE_NAME) 113 } 114 } 115 116 @RequiresApi(21) 117 internal object Api21Impl { getNoBackupFilesDirnull118 fun getNoBackupFilesDir(context: Context): File { 119 return context.noBackupFilesDir 120 } 121 } 122