blob: a96495de831693b52f7a296605383ff5332d347a [file] [log] [blame]
package com.android.launcher3;
import static com.android.launcher3.LauncherPrefs.NO_DB_FILES_RESTORED;
import android.app.backup.BackupAgent;
import android.app.backup.BackupDataInput;
import android.app.backup.BackupDataOutput;
import android.os.ParcelFileDescriptor;
import com.android.launcher3.logging.FileLog;
import com.android.launcher3.provider.RestoreDbTask;
import java.io.File;
import java.io.IOException;
import java.util.Arrays;
import java.util.stream.Collectors;
public class LauncherBackupAgent extends BackupAgent {
private static final String TAG = "LauncherBackupAgent";
private static final String DB_FILE_PREFIX = "launcher";
private static final String DB_FILE_SUFFIX = ".db";
@Override
public void onCreate() {
super.onCreate();
// Set the log dir as LauncherAppState is not initialized during restore.
FileLog.setDir(getFilesDir());
}
@Override
public void onRestore(
BackupDataInput data, int appVersionCode, ParcelFileDescriptor newState) {
// Doesn't do incremental backup/restore
}
@Override
public void onRestoreFile(ParcelFileDescriptor data, long size, File destination, int type,
long mode, long mtime) throws IOException {
// Remove old files which might contain obsolete attributes like idp_grid_name in shared
// preference that will obstruct backup's attribute from writing to shared preferences.
if (destination.delete()) {
FileLog.d(TAG, "onRestoreFile: Removed obsolete file " + destination);
}
super.onRestoreFile(data, size, destination, type, mode, mtime);
}
@Override
public void onBackup(
ParcelFileDescriptor oldState, BackupDataOutput data, ParcelFileDescriptor newState) {
// Doesn't do incremental backup/restore
}
@Override
public void onRestoreFinished() {
RestoreDbTask.setPending(this);
FileLog.d(TAG, "onRestoreFinished: set pending for RestoreDbTask");
markIfFilesWereNotActuallyRestored();
}
/**
* When restore is finished, we check to see if any db files were successfully restored. If not,
* our restore will fail later, but will report a different cause. This is important to split
* out the metric failures that are launcher's fault, and those that are due to bugs in the
* backup/restore code itself.
*/
private void markIfFilesWereNotActuallyRestored() {
File directory = new File(getDatabasePath(InvariantDeviceProfile.INSTANCE.get(this).dbFile)
.getParent());
if (!directory.exists()) {
FileLog.e(TAG, "restore failed as target database directory doesn't exist");
} else {
// Check for any db file that was restored, and collect as list
String fileNames = Arrays.stream(directory.listFiles())
.map(File::getName)
.filter(n -> n.startsWith(DB_FILE_PREFIX) && n.endsWith(DB_FILE_SUFFIX))
.collect(Collectors.joining(", "));
if (fileNames.isBlank()) {
FileLog.e(TAG, "no database files were successfully restored");
LauncherPrefs.get(this).putSync(NO_DB_FILES_RESTORED.to(true));
} else {
FileLog.d(TAG, "database files successfully restored: " + fileNames);
}
}
}
}