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