1 /* 2 * Copyright (C) 2009 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 17 package com.android.server; 18 19 20 import android.app.backup.BackupDataInput; 21 import android.app.backup.BackupDataOutput; 22 import android.app.backup.BackupAgentHelper; 23 import android.app.backup.FullBackup; 24 import android.app.backup.FullBackupDataOutput; 25 import android.app.backup.WallpaperBackupHelper; 26 import android.content.Context; 27 import android.os.Environment; 28 import android.os.ParcelFileDescriptor; 29 import android.os.ServiceManager; 30 import android.os.UserHandle; 31 import android.util.Slog; 32 33 34 import java.io.File; 35 import java.io.IOException; 36 37 /** 38 * Backup agent for various system-managed data, currently just the system wallpaper 39 */ 40 public class SystemBackupAgent extends BackupAgentHelper { 41 private static final String TAG = "SystemBackupAgent"; 42 43 // These paths must match what the WallpaperManagerService uses. The leaf *_FILENAME 44 // are also used in the full-backup file format, so must not change unless steps are 45 // taken to support the legacy backed-up datasets. 46 private static final String WALLPAPER_IMAGE_FILENAME = "wallpaper"; 47 private static final String WALLPAPER_INFO_FILENAME = "wallpaper_info.xml"; 48 49 // TODO: Will need to change if backing up non-primary user's wallpaper 50 private static final String WALLPAPER_IMAGE_DIR = 51 Environment.getUserSystemDirectory(UserHandle.USER_OWNER).getAbsolutePath(); 52 private static final String WALLPAPER_IMAGE = WallpaperBackupHelper.WALLPAPER_IMAGE; 53 54 // TODO: Will need to change if backing up non-primary user's wallpaper 55 private static final String WALLPAPER_INFO_DIR = 56 Environment.getUserSystemDirectory(UserHandle.USER_OWNER).getAbsolutePath(); 57 private static final String WALLPAPER_INFO = WallpaperBackupHelper.WALLPAPER_INFO; 58 // Use old keys to keep legacy data compatibility and avoid writing two wallpapers 59 private static final String WALLPAPER_IMAGE_KEY = WallpaperBackupHelper.WALLPAPER_IMAGE_KEY; 60 private static final String WALLPAPER_INFO_KEY = WallpaperBackupHelper.WALLPAPER_INFO_KEY; 61 62 @Override onBackup(ParcelFileDescriptor oldState, BackupDataOutput data, ParcelFileDescriptor newState)63 public void onBackup(ParcelFileDescriptor oldState, BackupDataOutput data, 64 ParcelFileDescriptor newState) throws IOException { 65 // We only back up the data under the current "wallpaper" schema with metadata 66 WallpaperManagerService wallpaper = (WallpaperManagerService)ServiceManager.getService( 67 Context.WALLPAPER_SERVICE); 68 String[] files = new String[] { WALLPAPER_IMAGE, WALLPAPER_INFO }; 69 String[] keys = new String[] { WALLPAPER_IMAGE_KEY, WALLPAPER_INFO_KEY }; 70 if (wallpaper != null && wallpaper.getName() != null && wallpaper.getName().length() > 0) { 71 // When the wallpaper has a name, back up the info by itself. 72 // TODO: Don't rely on the innards of the service object like this! 73 // TODO: Send a delete for any stored wallpaper image in this case? 74 files = new String[] { WALLPAPER_INFO }; 75 keys = new String[] { WALLPAPER_INFO_KEY }; 76 } 77 addHelper("wallpaper", new WallpaperBackupHelper(SystemBackupAgent.this, files, keys)); 78 super.onBackup(oldState, data, newState); 79 } 80 81 @Override onFullBackup(FullBackupDataOutput data)82 public void onFullBackup(FullBackupDataOutput data) throws IOException { 83 // At present we back up only the wallpaper 84 fullWallpaperBackup(data); 85 } 86 fullWallpaperBackup(FullBackupDataOutput output)87 private void fullWallpaperBackup(FullBackupDataOutput output) { 88 // Back up the data files directly. We do them in this specific order -- 89 // info file followed by image -- because then we need take no special 90 // steps during restore; the restore will happen properly when the individual 91 // files are restored piecemeal. 92 FullBackup.backupToTar(getPackageName(), FullBackup.ROOT_TREE_TOKEN, null, 93 WALLPAPER_INFO_DIR, WALLPAPER_INFO, output.getData()); 94 FullBackup.backupToTar(getPackageName(), FullBackup.ROOT_TREE_TOKEN, null, 95 WALLPAPER_IMAGE_DIR, WALLPAPER_IMAGE, output.getData()); 96 } 97 98 @Override onRestore(BackupDataInput data, int appVersionCode, ParcelFileDescriptor newState)99 public void onRestore(BackupDataInput data, int appVersionCode, ParcelFileDescriptor newState) 100 throws IOException { 101 // On restore, we also support a previous data schema "system_files" 102 addHelper("wallpaper", new WallpaperBackupHelper(SystemBackupAgent.this, 103 new String[] { WALLPAPER_IMAGE, WALLPAPER_INFO }, 104 new String[] { WALLPAPER_IMAGE_KEY, WALLPAPER_INFO_KEY} )); 105 addHelper("system_files", new WallpaperBackupHelper(SystemBackupAgent.this, 106 new String[] { WALLPAPER_IMAGE }, 107 new String[] { WALLPAPER_IMAGE_KEY} )); 108 109 try { 110 super.onRestore(data, appVersionCode, newState); 111 112 WallpaperManagerService wallpaper = (WallpaperManagerService)ServiceManager.getService( 113 Context.WALLPAPER_SERVICE); 114 wallpaper.settingsRestored(); 115 } catch (IOException ex) { 116 // If there was a failure, delete everything for the wallpaper, this is too aggressive, 117 // but this is hopefully a rare failure. 118 Slog.d(TAG, "restore failed", ex); 119 (new File(WALLPAPER_IMAGE)).delete(); 120 (new File(WALLPAPER_INFO)).delete(); 121 } 122 } 123 124 @Override onRestoreFile(ParcelFileDescriptor data, long size, int type, String domain, String path, long mode, long mtime)125 public void onRestoreFile(ParcelFileDescriptor data, long size, 126 int type, String domain, String path, long mode, long mtime) 127 throws IOException { 128 Slog.i(TAG, "Restoring file domain=" + domain + " path=" + path); 129 130 // Bits to indicate postprocessing we may need to perform 131 boolean restoredWallpaper = false; 132 133 File outFile = null; 134 // Various domain+files we understand a priori 135 if (domain.equals(FullBackup.ROOT_TREE_TOKEN)) { 136 if (path.equals(WALLPAPER_INFO_FILENAME)) { 137 outFile = new File(WALLPAPER_INFO); 138 restoredWallpaper = true; 139 } else if (path.equals(WALLPAPER_IMAGE_FILENAME)) { 140 outFile = new File(WALLPAPER_IMAGE); 141 restoredWallpaper = true; 142 } 143 } 144 145 try { 146 if (outFile == null) { 147 Slog.w(TAG, "Skipping unrecognized system file: [ " + domain + " : " + path + " ]"); 148 } 149 FullBackup.restoreFile(data, size, type, mode, mtime, outFile); 150 151 if (restoredWallpaper) { 152 WallpaperManagerService wallpaper = 153 (WallpaperManagerService)ServiceManager.getService( 154 Context.WALLPAPER_SERVICE); 155 wallpaper.settingsRestored(); 156 } 157 } catch (IOException e) { 158 if (restoredWallpaper) { 159 // Make sure we wind up in a good state 160 (new File(WALLPAPER_IMAGE)).delete(); 161 (new File(WALLPAPER_INFO)).delete(); 162 } 163 } 164 } 165 } 166