Home | History | Annotate | Download | only in backup
      1 /*
      2  * Copyright (C) 2014 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.annotation.Nullable;
     20 import android.app.backup.BackupManager;
     21 import android.app.backup.IBackupManager;
     22 import android.app.backup.IBackupObserver;
     23 import android.app.backup.IBackupManagerMonitor;
     24 import android.app.backup.IFullBackupRestoreObserver;
     25 import android.app.backup.IRestoreSession;
     26 import android.app.backup.ISelectBackupTransportCallback;
     27 import android.content.ComponentName;
     28 import android.content.Context;
     29 import android.content.Intent;
     30 import android.os.Binder;
     31 import android.os.Environment;
     32 import android.os.Handler;
     33 import android.os.HandlerThread;
     34 import android.os.IBinder;
     35 import android.os.ParcelFileDescriptor;
     36 import android.os.Process;
     37 import android.os.RemoteException;
     38 import android.os.SystemProperties;
     39 import android.os.Trace;
     40 import android.os.UserHandle;
     41 import android.util.Slog;
     42 
     43 import com.android.internal.util.DumpUtils;
     44 
     45 import java.io.File;
     46 import java.io.FileDescriptor;
     47 import java.io.IOException;
     48 import java.io.PrintWriter;
     49 
     50 
     51 /**
     52  * A proxy to BackupManagerService implementation.
     53  *
     54  * This is an external interface to the BackupManagerService which is being accessed via published
     55  * binder (see BackupManagerService$Lifecycle). This lets us turn down the heavy implementation
     56  * object on the fly without disturbing binders that have been cached somewhere in the system.
     57  *
     58  * This is where it is decided whether backup subsystem is available. It can be disabled with the
     59  * following two methods:
     60  *
     61  * <ul>
     62  * <li> Temporarily - create a file named Trampoline.BACKUP_SUPPRESS_FILENAME, or
     63  * <li> Product level - set Trampoline.BACKUP_DISABLE_PROPERTY system property to true.
     64  * </ul>
     65  */
     66 public class Trampoline extends IBackupManager.Stub {
     67     static final String TAG = "BackupManagerService";
     68     static final boolean DEBUG_TRAMPOLINE = false;
     69 
     70     // When this file is present, the backup service is inactive
     71     static final String BACKUP_SUPPRESS_FILENAME = "backup-suppress";
     72 
     73     // Product-level suppression of backup/restore
     74     static final String BACKUP_DISABLE_PROPERTY = "ro.backup.disable";
     75 
     76     final Context mContext;
     77     final File mSuppressFile;   // existence testing & creating synchronized on 'this'
     78     final boolean mGlobalDisable;
     79     volatile BackupManagerServiceInterface mService;
     80 
     81     private HandlerThread mHandlerThread;
     82 
     83     public Trampoline(Context context) {
     84         mContext = context;
     85         mGlobalDisable = isBackupDisabled();
     86         mSuppressFile = getSuppressFile();
     87         mSuppressFile.getParentFile().mkdirs();
     88     }
     89 
     90     protected boolean isBackupDisabled() {
     91         return SystemProperties.getBoolean(BACKUP_DISABLE_PROPERTY, false);
     92     }
     93 
     94     protected int binderGetCallingUid() {
     95         return Binder.getCallingUid();
     96     }
     97 
     98     protected File getSuppressFile() {
     99         return new File(new File(Environment.getDataDirectory(), "backup"),
    100                 BACKUP_SUPPRESS_FILENAME);
    101     }
    102 
    103     protected BackupManagerServiceInterface createBackupManagerService() {
    104         return BackupManagerService.create(mContext, this, mHandlerThread);
    105     }
    106 
    107     // internal control API
    108     public void initialize(final int whichUser) {
    109         // Note that only the owner user is currently involved in backup/restore
    110         // TODO: http://b/22388012
    111         if (whichUser == UserHandle.USER_SYSTEM) {
    112             // Does this product support backup/restore at all?
    113             if (mGlobalDisable) {
    114                 Slog.i(TAG, "Backup/restore not supported");
    115                 return;
    116             }
    117 
    118             synchronized (this) {
    119                 if (!mSuppressFile.exists()) {
    120                     mService = createBackupManagerService();
    121                 } else {
    122                     Slog.i(TAG, "Backup inactive in user " + whichUser);
    123                 }
    124             }
    125         }
    126     }
    127 
    128     void unlockSystemUser() {
    129         mHandlerThread = new HandlerThread("backup", Process.THREAD_PRIORITY_BACKGROUND);
    130         mHandlerThread.start();
    131 
    132         Handler h = new Handler(mHandlerThread.getLooper());
    133         h.post(() -> {
    134             Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "backup init");
    135             initialize(UserHandle.USER_SYSTEM);
    136             Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
    137 
    138             BackupManagerServiceInterface svc = mService;
    139             Slog.i(TAG, "Unlocking system user; mService=" + mService);
    140             if (svc != null) {
    141                 svc.unlockSystemUser();
    142             }
    143         });
    144     }
    145 
    146     public void setBackupServiceActive(final int userHandle, boolean makeActive) {
    147         // Only the DPM should be changing the active state of backup
    148         final int caller = binderGetCallingUid();
    149         if (caller != Process.SYSTEM_UID
    150                 && caller != Process.ROOT_UID) {
    151             throw new SecurityException("No permission to configure backup activity");
    152         }
    153 
    154         if (mGlobalDisable) {
    155             Slog.i(TAG, "Backup/restore not supported");
    156             return;
    157         }
    158         // TODO: http://b/22388012
    159         if (userHandle == UserHandle.USER_SYSTEM) {
    160             synchronized (this) {
    161                 if (makeActive != isBackupServiceActive(userHandle)) {
    162                     Slog.i(TAG, "Making backup "
    163                             + (makeActive ? "" : "in") + "active in user " + userHandle);
    164                     if (makeActive) {
    165                         mService = createBackupManagerService();
    166                         mSuppressFile.delete();
    167                     } else {
    168                         mService = null;
    169                         try {
    170                             mSuppressFile.createNewFile();
    171                         } catch (IOException e) {
    172                             Slog.e(TAG, "Unable to persist backup service inactivity");
    173                         }
    174                     }
    175                 }
    176             }
    177         }
    178     }
    179 
    180     // IBackupManager binder API
    181 
    182     /**
    183      * Querying activity state of backup service. Calling this method before initialize yields
    184      * undefined result.
    185      * @param userHandle The user in which the activity state of backup service is queried.
    186      * @return true if the service is active.
    187      */
    188     @Override
    189     public boolean isBackupServiceActive(final int userHandle) {
    190         // TODO: http://b/22388012
    191         if (userHandle == UserHandle.USER_SYSTEM) {
    192             synchronized (this) {
    193                 return mService != null;
    194             }
    195         }
    196         return false;
    197     }
    198 
    199     @Override
    200     public void dataChanged(String packageName) throws RemoteException {
    201         BackupManagerServiceInterface svc = mService;
    202         if (svc != null) {
    203             svc.dataChanged(packageName);
    204         }
    205     }
    206 
    207     @Override
    208     public void initializeTransports(String[] transportNames, IBackupObserver observer)
    209             throws RemoteException {
    210         BackupManagerServiceInterface svc = mService;
    211         if (svc != null) {
    212             svc.initializeTransports(transportNames, observer);
    213         }
    214     }
    215 
    216     @Override
    217     public void clearBackupData(String transportName, String packageName)
    218             throws RemoteException {
    219         BackupManagerServiceInterface svc = mService;
    220         if (svc != null) {
    221             svc.clearBackupData(transportName, packageName);
    222         }
    223     }
    224 
    225     @Override
    226     public void agentConnected(String packageName, IBinder agent) throws RemoteException {
    227         BackupManagerServiceInterface svc = mService;
    228         if (svc != null) {
    229             svc.agentConnected(packageName, agent);
    230         }
    231     }
    232 
    233     @Override
    234     public void agentDisconnected(String packageName) throws RemoteException {
    235         BackupManagerServiceInterface svc = mService;
    236         if (svc != null) {
    237             svc.agentDisconnected(packageName);
    238         }
    239     }
    240 
    241     @Override
    242     public void restoreAtInstall(String packageName, int token) throws RemoteException {
    243         BackupManagerServiceInterface svc = mService;
    244         if (svc != null) {
    245             svc.restoreAtInstall(packageName, token);
    246         }
    247     }
    248 
    249     @Override
    250     public void setBackupEnabled(boolean isEnabled) throws RemoteException {
    251         BackupManagerServiceInterface svc = mService;
    252         if (svc != null) {
    253             svc.setBackupEnabled(isEnabled);
    254         }
    255     }
    256 
    257     @Override
    258     public void setAutoRestore(boolean doAutoRestore) throws RemoteException {
    259         BackupManagerServiceInterface svc = mService;
    260         if (svc != null) {
    261             svc.setAutoRestore(doAutoRestore);
    262         }
    263     }
    264 
    265     @Override
    266     public void setBackupProvisioned(boolean isProvisioned) throws RemoteException {
    267         BackupManagerServiceInterface svc = mService;
    268         if (svc != null) {
    269             svc.setBackupProvisioned(isProvisioned);
    270         }
    271     }
    272 
    273     @Override
    274     public boolean isBackupEnabled() throws RemoteException {
    275         BackupManagerServiceInterface svc = mService;
    276         return (svc != null) ? svc.isBackupEnabled() : false;
    277     }
    278 
    279     @Override
    280     public boolean setBackupPassword(String currentPw, String newPw) throws RemoteException {
    281         BackupManagerServiceInterface svc = mService;
    282         return (svc != null) ? svc.setBackupPassword(currentPw, newPw) : false;
    283     }
    284 
    285     @Override
    286     public boolean hasBackupPassword() throws RemoteException {
    287         BackupManagerServiceInterface svc = mService;
    288         return (svc != null) ? svc.hasBackupPassword() : false;
    289     }
    290 
    291     @Override
    292     public void backupNow() throws RemoteException {
    293         BackupManagerServiceInterface svc = mService;
    294         if (svc != null) {
    295             svc.backupNow();
    296         }
    297     }
    298 
    299     @Override
    300     public void adbBackup(ParcelFileDescriptor fd, boolean includeApks, boolean includeObbs,
    301             boolean includeShared, boolean doWidgets, boolean allApps,
    302             boolean allIncludesSystem, boolean doCompress, boolean doKeyValue, String[] packageNames)
    303                     throws RemoteException {
    304         BackupManagerServiceInterface svc = mService;
    305         if (svc != null) {
    306             svc.adbBackup(fd, includeApks, includeObbs, includeShared, doWidgets,
    307                     allApps, allIncludesSystem, doCompress, doKeyValue, packageNames);
    308         }
    309     }
    310 
    311     @Override
    312     public void fullTransportBackup(String[] packageNames) throws RemoteException {
    313         BackupManagerServiceInterface svc = mService;
    314         if (svc != null) {
    315             svc.fullTransportBackup(packageNames);
    316         }
    317     }
    318 
    319     @Override
    320     public void adbRestore(ParcelFileDescriptor fd) throws RemoteException {
    321         BackupManagerServiceInterface svc = mService;
    322         if (svc != null) {
    323             svc.adbRestore(fd);
    324         }
    325     }
    326 
    327     @Override
    328     public void acknowledgeFullBackupOrRestore(int token, boolean allow, String curPassword,
    329             String encryptionPassword, IFullBackupRestoreObserver observer)
    330                     throws RemoteException {
    331         BackupManagerServiceInterface svc = mService;
    332         if (svc != null) {
    333             svc.acknowledgeAdbBackupOrRestore(token, allow,
    334                     curPassword, encryptionPassword, observer);
    335         }
    336     }
    337 
    338     @Override
    339     public String getCurrentTransport() throws RemoteException {
    340         BackupManagerServiceInterface svc = mService;
    341         return (svc != null) ? svc.getCurrentTransport() : null;
    342     }
    343 
    344     @Override
    345     public String[] listAllTransports() throws RemoteException {
    346         BackupManagerServiceInterface svc = mService;
    347         return (svc != null) ? svc.listAllTransports() : null;
    348     }
    349 
    350     @Override
    351     public ComponentName[] listAllTransportComponents() throws RemoteException {
    352         BackupManagerServiceInterface svc = mService;
    353         return (svc != null) ? svc.listAllTransportComponents() : null;
    354     }
    355 
    356     @Override
    357     public String[] getTransportWhitelist() {
    358         BackupManagerServiceInterface svc = mService;
    359         return (svc != null) ? svc.getTransportWhitelist() : null;
    360     }
    361 
    362     @Override
    363     public void updateTransportAttributes(
    364             ComponentName transportComponent,
    365             String name,
    366             @Nullable Intent configurationIntent,
    367             String currentDestinationString,
    368             @Nullable Intent dataManagementIntent,
    369             String dataManagementLabel) {
    370         BackupManagerServiceInterface svc = mService;
    371         if (svc != null) {
    372             svc.updateTransportAttributes(
    373                     transportComponent,
    374                     name,
    375                     configurationIntent,
    376                     currentDestinationString,
    377                     dataManagementIntent,
    378                     dataManagementLabel);
    379         }
    380     }
    381 
    382     @Override
    383     public String selectBackupTransport(String transport) throws RemoteException {
    384         BackupManagerServiceInterface svc = mService;
    385         return (svc != null) ? svc.selectBackupTransport(transport) : null;
    386     }
    387 
    388     @Override
    389     public void selectBackupTransportAsync(ComponentName transport,
    390             ISelectBackupTransportCallback listener) throws RemoteException {
    391         BackupManagerServiceInterface svc = mService;
    392         if (svc != null) {
    393             svc.selectBackupTransportAsync(transport, listener);
    394         } else {
    395             if (listener != null) {
    396                 try {
    397                     listener.onFailure(BackupManager.ERROR_BACKUP_NOT_ALLOWED);
    398                 } catch (RemoteException ex) {
    399                     // ignore
    400                 }
    401             }
    402         }
    403     }
    404 
    405     @Override
    406     public Intent getConfigurationIntent(String transport) throws RemoteException {
    407         BackupManagerServiceInterface svc = mService;
    408         return (svc != null) ? svc.getConfigurationIntent(transport) : null;
    409     }
    410 
    411     @Override
    412     public String getDestinationString(String transport) throws RemoteException {
    413         BackupManagerServiceInterface svc = mService;
    414         return (svc != null) ? svc.getDestinationString(transport) : null;
    415     }
    416 
    417     @Override
    418     public Intent getDataManagementIntent(String transport) throws RemoteException {
    419         BackupManagerServiceInterface svc = mService;
    420         return (svc != null) ? svc.getDataManagementIntent(transport) : null;
    421     }
    422 
    423     @Override
    424     public String getDataManagementLabel(String transport) throws RemoteException {
    425         BackupManagerServiceInterface svc = mService;
    426         return (svc != null) ? svc.getDataManagementLabel(transport) : null;
    427     }
    428 
    429     @Override
    430     public IRestoreSession beginRestoreSession(String packageName, String transportID)
    431             throws RemoteException {
    432         BackupManagerServiceInterface svc = mService;
    433         return (svc != null) ? svc.beginRestoreSession(packageName, transportID) : null;
    434     }
    435 
    436     @Override
    437     public void opComplete(int token, long result) throws RemoteException {
    438         BackupManagerServiceInterface svc = mService;
    439         if (svc != null) {
    440             svc.opComplete(token, result);
    441         }
    442     }
    443 
    444     @Override
    445     public long getAvailableRestoreToken(String packageName) {
    446         BackupManagerServiceInterface svc = mService;
    447         return (svc != null) ? svc.getAvailableRestoreToken(packageName) : 0;
    448     }
    449 
    450     @Override
    451     public boolean isAppEligibleForBackup(String packageName) {
    452         BackupManagerServiceInterface svc = mService;
    453         return (svc != null) ? svc.isAppEligibleForBackup(packageName) : false;
    454     }
    455 
    456     @Override
    457     public String[] filterAppsEligibleForBackup(String[] packages) {
    458         BackupManagerServiceInterface svc = mService;
    459         return (svc != null) ? svc.filterAppsEligibleForBackup(packages) : null;
    460     }
    461 
    462     @Override
    463     public int requestBackup(String[] packages, IBackupObserver observer,
    464             IBackupManagerMonitor monitor, int flags) throws RemoteException {
    465         BackupManagerServiceInterface svc = mService;
    466         if (svc == null) {
    467             return BackupManager.ERROR_BACKUP_NOT_ALLOWED;
    468         }
    469         return svc.requestBackup(packages, observer, monitor, flags);
    470     }
    471 
    472     @Override
    473     public void cancelBackups() throws RemoteException {
    474         BackupManagerServiceInterface svc = mService;
    475         if (svc != null) {
    476             svc.cancelBackups();
    477         }
    478     }
    479 
    480     @Override
    481     public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
    482         if (!DumpUtils.checkDumpPermission(mContext, TAG, pw)) return;
    483 
    484         BackupManagerServiceInterface svc = mService;
    485         if (svc != null) {
    486             svc.dump(fd, pw, args);
    487         } else {
    488             pw.println("Inactive");
    489         }
    490     }
    491 
    492     // Full backup/restore entry points - non-Binder; called directly
    493     // by the full-backup scheduled job
    494     /* package */ boolean beginFullBackup(FullBackupJob scheduledJob) {
    495         BackupManagerServiceInterface svc = mService;
    496         return (svc != null) ? svc.beginFullBackup(scheduledJob) : false;
    497     }
    498 
    499     /* package */ void endFullBackup() {
    500         BackupManagerServiceInterface svc = mService;
    501         if (svc != null) {
    502             svc.endFullBackup();
    503         }
    504     }
    505 }
    506