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