Home | History | Annotate | Download | only in backup
      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 
     20 import android.app.ActivityManagerNative;
     21 import android.app.IWallpaperManager;
     22 import android.app.backup.BackupDataInput;
     23 import android.app.backup.BackupDataOutput;
     24 import android.app.backup.BackupAgentHelper;
     25 import android.app.backup.FullBackup;
     26 import android.app.backup.FullBackupDataOutput;
     27 import android.app.backup.RecentsBackupHelper;
     28 import android.app.backup.WallpaperBackupHelper;
     29 import android.content.Context;
     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.util.Slog;
     36 
     37 import java.io.File;
     38 import java.io.IOException;
     39 
     40 /**
     41  * Backup agent for various system-managed data, currently just the system wallpaper
     42  */
     43 public 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