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