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.backup; 18 19 import android.app.IWallpaperManager; 20 import android.app.backup.BackupAgentHelper; 21 import android.app.backup.BackupAnnotations.BackupDestination; 22 import android.app.backup.BackupDataInput; 23 import android.app.backup.BackupHelperWithLogger; 24 import android.app.backup.BackupRestoreEventLogger; 25 import android.app.backup.FullBackup; 26 import android.app.backup.FullBackupDataOutput; 27 import android.app.backup.WallpaperBackupHelper; 28 import android.content.Context; 29 import android.content.pm.PackageManager; 30 import android.os.Environment; 31 import android.os.ParcelFileDescriptor; 32 import android.os.RemoteException; 33 import android.os.ServiceManager; 34 import android.os.UserHandle; 35 import android.os.UserManager; 36 import android.util.Slog; 37 38 import com.android.server.backup.Flags; 39 40 import com.google.android.collect.Sets; 41 42 import java.io.File; 43 import java.io.IOException; 44 import java.util.Set; 45 46 /** 47 * Backup agent for various system-managed data. Wallpapers are now handled by a 48 * separate package, but we still process restores from legacy datasets here. 49 */ 50 public class SystemBackupAgent extends BackupAgentHelper { 51 private static final String TAG = "SystemBackupAgent"; 52 53 // Names of the helper tags within the dataset. Changing one of these names will 54 // break the ability to restore from datasets that predate the change. 55 private static final String WALLPAPER_HELPER = "wallpaper"; 56 private static final String SYNC_SETTINGS_HELPER = "account_sync_settings"; 57 private static final String PREFERRED_HELPER = "preferred_activities"; 58 private static final String NOTIFICATION_HELPER = "notifications"; 59 private static final String PERMISSION_HELPER = "permissions"; 60 private static final String USAGE_STATS_HELPER = "usage_stats"; 61 private static final String SHORTCUT_MANAGER_HELPER = "shortcut_manager"; 62 private static final String ACCOUNT_MANAGER_HELPER = "account_manager"; 63 private static final String SLICES_HELPER = "slices"; 64 private static final String PEOPLE_HELPER = "people"; 65 private static final String APP_LOCALES_HELPER = "app_locales"; 66 private static final String APP_GENDER_HELPER = "app_gender"; 67 private static final String COMPANION_HELPER = "companion"; 68 private static final String SYSTEM_GENDER_HELPER = "system_gender"; 69 70 // These paths must match what the WallpaperManagerService uses. The leaf *_FILENAME 71 // are also used in the full-backup file format, so must not change unless steps are 72 // taken to support the legacy backed-up datasets. 73 private static final String WALLPAPER_IMAGE_FILENAME = "wallpaper"; 74 private static final String WALLPAPER_INFO_FILENAME = "wallpaper_info.xml"; 75 76 // TODO: Will need to change if backing up non-primary user's wallpaper 77 // TODO: http://b/22388012 78 private static final String WALLPAPER_IMAGE_DIR = 79 Environment.getUserSystemDirectory(UserHandle.USER_SYSTEM).getAbsolutePath(); 80 public static final String WALLPAPER_IMAGE = 81 new File(Environment.getUserSystemDirectory(UserHandle.USER_SYSTEM), 82 "wallpaper").getAbsolutePath(); 83 84 // TODO: Will need to change if backing up non-primary user's wallpaper 85 // TODO: http://b/22388012 86 private static final String WALLPAPER_INFO_DIR = 87 Environment.getUserSystemDirectory(UserHandle.USER_SYSTEM).getAbsolutePath(); 88 public static final String WALLPAPER_INFO = 89 new File(Environment.getUserSystemDirectory(UserHandle.USER_SYSTEM), 90 "wallpaper_info.xml").getAbsolutePath(); 91 // Use old keys to keep legacy data compatibility and avoid writing two wallpapers 92 private static final String WALLPAPER_IMAGE_KEY = WallpaperBackupHelper.WALLPAPER_IMAGE_KEY; 93 94 /** 95 * Helpers that are enabled for "profile" users (such as work profile). See {@link 96 * UserManager#isProfile()}. This is a subset of {@link #sEligibleHelpersForNonSystemUser}. 97 */ 98 private static final Set<String> sEligibleHelpersForProfileUser = 99 Sets.newArraySet( 100 PERMISSION_HELPER, 101 NOTIFICATION_HELPER, 102 SYNC_SETTINGS_HELPER, 103 APP_LOCALES_HELPER, 104 COMPANION_HELPER, 105 APP_GENDER_HELPER, 106 SYSTEM_GENDER_HELPER); 107 108 /** Helpers that are enabled for full, non-system users. */ 109 private static final Set<String> sEligibleHelpersForNonSystemUser = 110 SetUtils.union(sEligibleHelpersForProfileUser, 111 Sets.newArraySet(ACCOUNT_MANAGER_HELPER, USAGE_STATS_HELPER, PREFERRED_HELPER, 112 SHORTCUT_MANAGER_HELPER)); 113 114 private int mUserId = UserHandle.USER_SYSTEM; 115 private boolean mIsProfileUser = false; 116 private BackupRestoreEventLogger mLogger; 117 118 @Override onCreate(UserHandle user, @BackupDestination int backupDestination)119 public void onCreate(UserHandle user, @BackupDestination int backupDestination) { 120 super.onCreate(user, backupDestination); 121 mLogger = this.getBackupRestoreEventLogger(); 122 123 mUserId = user.getIdentifier(); 124 if (mUserId != UserHandle.USER_SYSTEM) { 125 Context context = createContextAsUser(user, /* flags= */ 0); 126 UserManager userManager = context.getSystemService(UserManager.class); 127 mIsProfileUser = userManager.isProfile(); 128 } 129 130 addHelperIfEligibleForUser( 131 SYNC_SETTINGS_HELPER, new AccountSyncSettingsBackupHelper(this, mUserId)); 132 addHelperIfEligibleForUser(PREFERRED_HELPER, new PreferredActivityBackupHelper(mUserId)); 133 addHelperIfEligibleForUser(NOTIFICATION_HELPER, new NotificationBackupHelper(mUserId)); 134 addHelperIfEligibleForUser(PERMISSION_HELPER, new PermissionBackupHelper(mUserId)); 135 addHelperIfEligibleForUser(USAGE_STATS_HELPER, new UsageStatsBackupHelper(mUserId)); 136 addHelperIfEligibleForUser(SHORTCUT_MANAGER_HELPER, new ShortcutBackupHelper(mUserId)); 137 addHelperIfEligibleForUser(ACCOUNT_MANAGER_HELPER, new AccountManagerBackupHelper(mUserId)); 138 if (!getPackageManager().hasSystemFeature(PackageManager.FEATURE_SLICES_DISABLED)) { 139 addHelperIfEligibleForUser(SLICES_HELPER, new SliceBackupHelper(this)); 140 } 141 addHelperIfEligibleForUser(PEOPLE_HELPER, new PeopleBackupHelper(mUserId)); 142 addHelperIfEligibleForUser(APP_LOCALES_HELPER, new AppSpecificLocalesBackupHelper(mUserId)); 143 addHelperIfEligibleForUser(APP_GENDER_HELPER, 144 new AppGrammaticalGenderBackupHelper(mUserId)); 145 addHelperIfEligibleForUser(COMPANION_HELPER, new CompanionBackupHelper(mUserId)); 146 addHelperIfEligibleForUser(SYSTEM_GENDER_HELPER, 147 new SystemGrammaticalGenderBackupHelper(mUserId)); 148 } 149 150 @Override onFullBackup(FullBackupDataOutput data)151 public void onFullBackup(FullBackupDataOutput data) throws IOException { 152 // At present we don't back up anything 153 } 154 155 @Override onRestore(BackupDataInput data, int appVersionCode, ParcelFileDescriptor newState)156 public void onRestore(BackupDataInput data, int appVersionCode, ParcelFileDescriptor newState) 157 throws IOException { 158 // Slot in a restore helper for the older wallpaper backup schema to support restore 159 // from devices still generating data in that format. 160 //TODO(b/147732386): Add multi-display support for wallpaper backup. 161 addHelper(WALLPAPER_HELPER, new WallpaperBackupHelper(this, 162 new String[] { WALLPAPER_IMAGE_KEY})); 163 164 // On restore, we also support a long-ago wallpaper data schema "system_files" 165 addHelper("system_files", new WallpaperBackupHelper(this, 166 new String[] { WALLPAPER_IMAGE_KEY} )); 167 168 super.onRestore(data, appVersionCode, newState); 169 } 170 171 /** 172 * Support for 'adb restore' of legacy archives 173 */ 174 @Override onRestoreFile(ParcelFileDescriptor data, long size, int type, String domain, String path, long mode, long mtime)175 public void onRestoreFile(ParcelFileDescriptor data, long size, 176 int type, String domain, String path, long mode, long mtime) 177 throws IOException { 178 Slog.i(TAG, "Restoring file domain=" + domain + " path=" + path); 179 180 // Bits to indicate postprocessing we may need to perform 181 boolean restoredWallpaper = false; 182 183 File outFile = null; 184 // Various domain+files we understand a priori 185 if (domain.equals(FullBackup.ROOT_TREE_TOKEN)) { 186 if (path.equals(WALLPAPER_INFO_FILENAME)) { 187 outFile = new File(WALLPAPER_INFO); 188 restoredWallpaper = true; 189 } else if (path.equals(WALLPAPER_IMAGE_FILENAME)) { 190 outFile = new File(WALLPAPER_IMAGE); 191 restoredWallpaper = true; 192 } 193 } 194 195 try { 196 if (outFile == null) { 197 Slog.w(TAG, "Skipping unrecognized system file: [ " + domain + " : " + path + " ]"); 198 } 199 FullBackup.restoreFile(data, size, type, mode, mtime, outFile); 200 201 if (restoredWallpaper) { 202 IWallpaperManager wallpaper = 203 (IWallpaperManager)ServiceManager.getService( 204 Context.WALLPAPER_SERVICE); 205 if (wallpaper != null) { 206 try { 207 wallpaper.settingsRestored(); 208 } catch (RemoteException re) { 209 Slog.e(TAG, "Couldn't restore settings\n" + re); 210 } 211 } 212 } 213 } catch (IOException e) { 214 if (restoredWallpaper) { 215 // Make sure we wind up in a good state 216 (new File(WALLPAPER_IMAGE)).delete(); 217 (new File(WALLPAPER_INFO)).delete(); 218 } 219 } 220 } 221 addHelperIfEligibleForUser(String keyPrefix, BackupHelperWithLogger helper)222 private void addHelperIfEligibleForUser(String keyPrefix, BackupHelperWithLogger helper) { 223 if (isHelperEligibleForUser(keyPrefix)) { 224 addHelper(keyPrefix, helper); 225 if (Flags.enableMetricsSystemBackupAgents()) { 226 helper.setLogger(mLogger); 227 } 228 } 229 } 230 isHelperEligibleForUser(String keyPrefix)231 private boolean isHelperEligibleForUser(String keyPrefix) { 232 // All helpers are eligible for the system user. 233 if (mUserId == UserHandle.USER_SYSTEM) { 234 return true; 235 } 236 237 // Profile users (such as work profile) have their own allow list. 238 if (mIsProfileUser) { 239 return sEligibleHelpersForProfileUser.contains(keyPrefix); 240 } 241 242 // Full, non-system users have their own allow list. 243 return sEligibleHelpersForNonSystemUser.contains(keyPrefix); 244 } 245 } 246