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