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