diff options
Diffstat (limited to 'services/backup')
3 files changed, 348 insertions, 20 deletions
diff --git a/services/backup/java/com/android/server/backup/BackupManagerService.java b/services/backup/java/com/android/server/backup/BackupManagerService.java index fea1a7a..6c2681b 100644 --- a/services/backup/java/com/android/server/backup/BackupManagerService.java +++ b/services/backup/java/com/android/server/backup/BackupManagerService.java @@ -153,7 +153,7 @@ import javax.crypto.spec.SecretKeySpec; import libcore.io.IoUtils; -public class BackupManagerService extends IBackupManager.Stub { +public class BackupManagerService { private static final String TAG = "BackupManagerService"; private static final boolean DEBUG = true; @@ -322,8 +322,12 @@ public class BackupManagerService extends IBackupManager.Stub { // Watch the device provisioning operation during setup ContentObserver mProvisionedObserver; - static BackupManagerService sInstance; - static BackupManagerService getInstance() { + // The published binder is actually to a singleton trampoline object that calls + // through to the proper code. This indirection lets us turn down the heavy + // implementation object on the fly without disturbing binders that have been + // cached elsewhere in the system. + static Trampoline sInstance; + static Trampoline getInstance() { // Always constructed during system bringup, so no need to lazy-init return sInstance; } @@ -332,7 +336,7 @@ public class BackupManagerService extends IBackupManager.Stub { public Lifecycle(Context context) { super(context); - sInstance = new BackupManagerService(context); + sInstance = new Trampoline(context); } @Override @@ -342,11 +346,17 @@ public class BackupManagerService extends IBackupManager.Stub { @Override public void onBootPhase(int phase) { - if (phase == PHASE_THIRD_PARTY_APPS_CAN_START) { + if (phase == PHASE_SYSTEM_SERVICES_READY) { + sInstance.initialize(UserHandle.USER_OWNER); + } else if (phase == PHASE_THIRD_PARTY_APPS_CAN_START) { ContentResolver r = sInstance.mContext.getContentResolver(); boolean areEnabled = Settings.Secure.getInt(r, Settings.Secure.BACKUP_ENABLED, 0) != 0; - sInstance.setBackupEnabled(areEnabled); + try { + sInstance.setBackupEnabled(areEnabled); + } catch (RemoteException e) { + // can't happen; it's a local object + } } } } @@ -934,7 +944,7 @@ public class BackupManagerService extends IBackupManager.Stub { // ----- Main service implementation ----- - public BackupManagerService(Context context) { + public BackupManagerService(Context context, Trampoline parent) { mContext = context; mPackageManager = context.getPackageManager(); mPackageManagerBinder = AppGlobals.getPackageManager(); @@ -944,7 +954,7 @@ public class BackupManagerService extends IBackupManager.Stub { mPowerManager = (PowerManager) context.getSystemService(Context.POWER_SERVICE); mMountService = IMountService.Stub.asInterface(ServiceManager.getService("mount")); - mBackupManagerBinder = asInterface(asBinder()); + mBackupManagerBinder = Trampoline.asInterface(parent.asBinder()); // spin up the backup/restore handler thread mHandlerThread = new HandlerThread("backup", Process.THREAD_PRIORITY_BACKGROUND); @@ -1451,7 +1461,6 @@ public class BackupManagerService extends IBackupManager.Stub { return false; } - @Override public boolean setBackupPassword(String currentPw, String newPw) { mContext.enforceCallingOrSelfPermission(android.Manifest.permission.BACKUP, "setBackupPassword"); @@ -1532,7 +1541,6 @@ public class BackupManagerService extends IBackupManager.Stub { return false; } - @Override public boolean hasBackupPassword() { mContext.enforceCallingOrSelfPermission(android.Manifest.permission.BACKUP, "hasBackupPassword"); @@ -8145,7 +8153,6 @@ if (MORE_DEBUG) Slog.v(TAG, " + got " + nRead + "; now wanting " + (size - soF // // This is the variant used by 'adb backup'; it requires on-screen confirmation // by the user because it can be used to offload data over untrusted USB. - @Override public void fullBackup(ParcelFileDescriptor fd, boolean includeApks, boolean includeObbs, boolean includeShared, boolean doWidgets, boolean doAllApps, boolean includeSystem, boolean compress, String[] pkgList) { @@ -8217,7 +8224,6 @@ if (MORE_DEBUG) Slog.v(TAG, " + got " + nRead + "; now wanting " + (size - soF } } - @Override public void fullTransportBackup(String[] pkgNames) { mContext.enforceCallingPermission(android.Manifest.permission.BACKUP, "fullTransportBackup"); @@ -8247,7 +8253,6 @@ if (MORE_DEBUG) Slog.v(TAG, " + got " + nRead + "; now wanting " + (size - soF } } - @Override public void fullRestore(ParcelFileDescriptor fd) { mContext.enforceCallingPermission(android.Manifest.permission.BACKUP, "fullRestore"); @@ -8343,7 +8348,6 @@ if (MORE_DEBUG) Slog.v(TAG, " + got " + nRead + "; now wanting " + (size - soF // Confirm that the previously-requested full backup/restore operation can proceed. This // is used to require a user-facing disclosure about the operation. - @Override public void acknowledgeFullBackupOrRestore(int token, boolean allow, String curPassword, String encPpassword, IFullBackupRestoreObserver observer) { if (DEBUG) Slog.d(TAG, "acknowledgeFullBackupOrRestore : token=" + token @@ -8391,8 +8395,7 @@ if (MORE_DEBUG) Slog.v(TAG, " + got " + nRead + "; now wanting " + (size - soF } } - // Enable/disable the backup service - @Override + // Enable/disable backups public void setBackupEnabled(boolean enable) { mContext.enforceCallingOrSelfPermission(android.Manifest.permission.BACKUP, "setBackupEnabled"); @@ -8798,7 +8801,6 @@ if (MORE_DEBUG) Slog.v(TAG, " + got " + nRead + "; now wanting " + (size - soF // Note that a currently-active backup agent has notified us that it has // completed the given outstanding asynchronous backup/restore operation. - @Override public void opComplete(int token) { if (MORE_DEBUG) Slog.v(TAG, "opComplete: " + Integer.toHexString(token)); Operation op = null; @@ -9147,7 +9149,6 @@ if (MORE_DEBUG) Slog.v(TAG, " + got " + nRead + "; now wanting " + (size - soF } } - @Override public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { mContext.enforceCallingOrSelfPermission(android.Manifest.permission.DUMP, TAG); diff --git a/services/backup/java/com/android/server/backup/FullBackupJob.java b/services/backup/java/com/android/server/backup/FullBackupJob.java index 601f15e..7ad7657c 100644 --- a/services/backup/java/com/android/server/backup/FullBackupJob.java +++ b/services/backup/java/com/android/server/backup/FullBackupJob.java @@ -59,7 +59,7 @@ public class FullBackupJob extends JobService { @Override public boolean onStartJob(JobParameters params) { mParams = params; - BackupManagerService service = BackupManagerService.getInstance(); + Trampoline service = BackupManagerService.getInstance(); return service.beginFullBackup(this); } @@ -67,7 +67,7 @@ public class FullBackupJob extends JobService { public boolean onStopJob(JobParameters params) { if (mParams != null) { mParams = null; - BackupManagerService service = BackupManagerService.getInstance(); + Trampoline service = BackupManagerService.getInstance(); service.endFullBackup(); } return false; diff --git a/services/backup/java/com/android/server/backup/Trampoline.java b/services/backup/java/com/android/server/backup/Trampoline.java new file mode 100644 index 0000000..5d2187f --- /dev/null +++ b/services/backup/java/com/android/server/backup/Trampoline.java @@ -0,0 +1,327 @@ +/* + * Copyright (C) 2014 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.server.backup; + +import android.app.backup.IBackupManager; +import android.app.backup.IFullBackupRestoreObserver; +import android.app.backup.IRestoreSession; +import android.content.Context; +import android.content.Intent; +import android.os.Binder; +import android.os.Environment; +import android.os.IBinder; +import android.os.ParcelFileDescriptor; +import android.os.Process; +import android.os.RemoteException; +import android.os.SystemProperties; +import android.os.UserHandle; +import android.util.Slog; + +import java.io.File; +import java.io.FileDescriptor; +import java.io.IOException; +import java.io.PrintWriter; + +public class Trampoline extends IBackupManager.Stub { + static final String TAG = "BackupManagerService"; + static final boolean DEBUG_TRAMPOLINE = false; + + // When this file is present, the backup service is inactive + static final String BACKUP_SUPPRESS_FILENAME = "backup-suppress"; + + // Product-level suppression of backup/restore + static final String BACKUP_DISABLE_PROPERTY = "ro.backup.disable"; + + final Context mContext; + final File mSuppressFile; // existence testing & creating synchronized on 'this' + final boolean mGlobalDisable; + volatile BackupManagerService mService; + + public Trampoline(Context context) { + mContext = context; + File dir = new File(Environment.getSecureDataDirectory(), "backup"); + dir.mkdirs(); + mSuppressFile = new File(dir, BACKUP_SUPPRESS_FILENAME); + mGlobalDisable = SystemProperties.getBoolean(BACKUP_DISABLE_PROPERTY, false); + } + + // internal control API + public void initialize(final int whichUser) { + // Note that only the owner user is currently involved in backup/restore + if (whichUser == UserHandle.USER_OWNER) { + // Does this product support backup/restore at all? + if (mGlobalDisable) { + Slog.i(TAG, "Backup/restore not supported"); + return; + } + + synchronized (this) { + if (!mSuppressFile.exists()) { + mService = new BackupManagerService(mContext, this); + } else { + Slog.i(TAG, "Backup inactive in user " + whichUser); + } + } + } + } + + public void setBackupServiceActive(final int userHandle, boolean makeActive) { + // Only the DPM should be changing the active state of backup + final int caller = Binder.getCallingUid(); + if (caller != Process.SYSTEM_UID + && caller != Process.ROOT_UID) { + throw new SecurityException("No permission to configure backup activity"); + } + + if (mGlobalDisable) { + Slog.i(TAG, "Backup/restore not supported"); + return; + } + + if (userHandle == UserHandle.USER_OWNER) { + synchronized (this) { + if (makeActive != (mService != null)) { + Slog.i(TAG, "Making backup " + + (makeActive ? "" : "in") + "active in user " + userHandle); + if (makeActive) { + mService = new BackupManagerService(mContext, this); + mSuppressFile.delete(); + } else { + mService = null; + try { + mSuppressFile.createNewFile(); + } catch (IOException e) { + Slog.e(TAG, "Unable to persist backup service inactivity"); + } + } + } + } + } + } + + // IBackupManager binder API + @Override + public void dataChanged(String packageName) throws RemoteException { + BackupManagerService svc = mService; + if (svc != null) { + svc.dataChanged(packageName); + } + } + + @Override + public void clearBackupData(String transportName, String packageName) + throws RemoteException { + BackupManagerService svc = mService; + if (svc != null) { + svc.clearBackupData(transportName, packageName); + } + } + + @Override + public void agentConnected(String packageName, IBinder agent) throws RemoteException { + BackupManagerService svc = mService; + if (svc != null) { + svc.agentConnected(packageName, agent); + } + } + + @Override + public void agentDisconnected(String packageName) throws RemoteException { + BackupManagerService svc = mService; + if (svc != null) { + svc.agentDisconnected(packageName); + } + } + + @Override + public void restoreAtInstall(String packageName, int token) throws RemoteException { + BackupManagerService svc = mService; + if (svc != null) { + svc.restoreAtInstall(packageName, token); + } + } + + @Override + public void setBackupEnabled(boolean isEnabled) throws RemoteException { + BackupManagerService svc = mService; + if (svc != null) { + svc.setBackupEnabled(isEnabled); + } + } + + @Override + public void setAutoRestore(boolean doAutoRestore) throws RemoteException { + BackupManagerService svc = mService; + if (svc != null) { + svc.setAutoRestore(doAutoRestore); + } + } + + @Override + public void setBackupProvisioned(boolean isProvisioned) throws RemoteException { + BackupManagerService svc = mService; + if (svc != null) { + svc.setBackupProvisioned(isProvisioned); + } + } + + @Override + public boolean isBackupEnabled() throws RemoteException { + BackupManagerService svc = mService; + return (svc != null) ? svc.isBackupEnabled() : false; + } + + @Override + public boolean setBackupPassword(String currentPw, String newPw) throws RemoteException { + BackupManagerService svc = mService; + return (svc != null) ? svc.setBackupPassword(currentPw, newPw) : false; + } + + @Override + public boolean hasBackupPassword() throws RemoteException { + BackupManagerService svc = mService; + return (svc != null) ? svc.hasBackupPassword() : false; + } + + @Override + public void backupNow() throws RemoteException { + BackupManagerService svc = mService; + if (svc != null) { + svc.backupNow(); + } + } + + @Override + public void fullBackup(ParcelFileDescriptor fd, boolean includeApks, boolean includeObbs, + boolean includeShared, boolean doWidgets, boolean allApps, + boolean allIncludesSystem, boolean doCompress, String[] packageNames) + throws RemoteException { + BackupManagerService svc = mService; + if (svc != null) { + svc.fullBackup(fd, includeApks, includeObbs, includeShared, doWidgets, + allApps, allIncludesSystem, doCompress, packageNames); + } + } + + @Override + public void fullTransportBackup(String[] packageNames) throws RemoteException { + BackupManagerService svc = mService; + if (svc != null) { + svc.fullTransportBackup(packageNames); + } + } + + @Override + public void fullRestore(ParcelFileDescriptor fd) throws RemoteException { + BackupManagerService svc = mService; + if (svc != null) { + svc.fullRestore(fd); + } + } + + @Override + public void acknowledgeFullBackupOrRestore(int token, boolean allow, String curPassword, + String encryptionPassword, IFullBackupRestoreObserver observer) + throws RemoteException { + BackupManagerService svc = mService; + if (svc != null) { + svc.acknowledgeFullBackupOrRestore(token, allow, + curPassword, encryptionPassword, observer); + } + } + + @Override + public String getCurrentTransport() throws RemoteException { + BackupManagerService svc = mService; + return (svc != null) ? svc.getCurrentTransport() : null; + } + + @Override + public String[] listAllTransports() throws RemoteException { + BackupManagerService svc = mService; + return (svc != null) ? svc.listAllTransports() : null; + } + + @Override + public String selectBackupTransport(String transport) throws RemoteException { + BackupManagerService svc = mService; + return (svc != null) ? svc.selectBackupTransport(transport) : null; + } + + @Override + public Intent getConfigurationIntent(String transport) throws RemoteException { + BackupManagerService svc = mService; + return (svc != null) ? svc.getConfigurationIntent(transport) : null; + } + + @Override + public String getDestinationString(String transport) throws RemoteException { + BackupManagerService svc = mService; + return (svc != null) ? svc.getDestinationString(transport) : null; + } + + @Override + public Intent getDataManagementIntent(String transport) throws RemoteException { + BackupManagerService svc = mService; + return (svc != null) ? svc.getDataManagementIntent(transport) : null; + } + + @Override + public String getDataManagementLabel(String transport) throws RemoteException { + BackupManagerService svc = mService; + return (svc != null) ? svc.getDataManagementLabel(transport) : null; + } + + @Override + public IRestoreSession beginRestoreSession(String packageName, String transportID) + throws RemoteException { + BackupManagerService svc = mService; + return (svc != null) ? svc.beginRestoreSession(packageName, transportID) : null; + } + + @Override + public void opComplete(int token) throws RemoteException { + BackupManagerService svc = mService; + if (svc != null) { + svc.opComplete(token); + } + } + + @Override + public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { + BackupManagerService svc = mService; + if (svc != null) { + svc.dump(fd, pw, args); + } else { + pw.println("Inactive"); + } + } + + // Full backup/restore entry points - non-Binder; called directly + // by the full-backup scheduled job + /* package */ boolean beginFullBackup(FullBackupJob scheduledJob) { + BackupManagerService svc = mService; + return (svc != null) ? svc.beginFullBackup(scheduledJob) : false; + } + + /* package */ void endFullBackup() { + BackupManagerService svc = mService; + if (svc != null) { + svc.endFullBackup(); + } + } +} |