Merge change 6162 into donut
* changes: Hold a wakelock during backup/restore/clear operations
This commit is contained in:
@ -17,9 +17,11 @@
|
|||||||
package com.android.server;
|
package com.android.server;
|
||||||
|
|
||||||
import android.app.ActivityManagerNative;
|
import android.app.ActivityManagerNative;
|
||||||
|
import android.app.AlarmManager;
|
||||||
import android.app.IActivityManager;
|
import android.app.IActivityManager;
|
||||||
import android.app.IApplicationThread;
|
import android.app.IApplicationThread;
|
||||||
import android.app.IBackupAgent;
|
import android.app.IBackupAgent;
|
||||||
|
import android.app.PendingIntent;
|
||||||
import android.content.BroadcastReceiver;
|
import android.content.BroadcastReceiver;
|
||||||
import android.content.ComponentName;
|
import android.content.ComponentName;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
@ -41,6 +43,7 @@ import android.os.Handler;
|
|||||||
import android.os.IBinder;
|
import android.os.IBinder;
|
||||||
import android.os.Message;
|
import android.os.Message;
|
||||||
import android.os.ParcelFileDescriptor;
|
import android.os.ParcelFileDescriptor;
|
||||||
|
import android.os.PowerManager;
|
||||||
import android.os.Process;
|
import android.os.Process;
|
||||||
import android.os.RemoteException;
|
import android.os.RemoteException;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
@ -76,8 +79,9 @@ class BackupManagerService extends IBackupManager.Stub {
|
|||||||
|
|
||||||
// How often we perform a backup pass. Privileged external callers can
|
// How often we perform a backup pass. Privileged external callers can
|
||||||
// trigger an immediate pass.
|
// trigger an immediate pass.
|
||||||
private static final long BACKUP_INTERVAL = 60 * 60 * 1000;
|
private static final long BACKUP_INTERVAL = AlarmManager.INTERVAL_HOUR;
|
||||||
|
|
||||||
|
private static final String RUN_BACKUP_ACTION = "_backup_run_";
|
||||||
private static final int MSG_RUN_BACKUP = 1;
|
private static final int MSG_RUN_BACKUP = 1;
|
||||||
private static final int MSG_RUN_FULL_BACKUP = 2;
|
private static final int MSG_RUN_FULL_BACKUP = 2;
|
||||||
private static final int MSG_RUN_RESTORE = 3;
|
private static final int MSG_RUN_RESTORE = 3;
|
||||||
@ -89,8 +93,15 @@ class BackupManagerService extends IBackupManager.Stub {
|
|||||||
private Context mContext;
|
private Context mContext;
|
||||||
private PackageManager mPackageManager;
|
private PackageManager mPackageManager;
|
||||||
private IActivityManager mActivityManager;
|
private IActivityManager mActivityManager;
|
||||||
|
private PowerManager mPowerManager;
|
||||||
|
private AlarmManager mAlarmManager;
|
||||||
|
|
||||||
private boolean mEnabled; // access to this is synchronized on 'this'
|
private boolean mEnabled; // access to this is synchronized on 'this'
|
||||||
|
private PowerManager.WakeLock mWakelock;
|
||||||
private final BackupHandler mBackupHandler = new BackupHandler();
|
private final BackupHandler mBackupHandler = new BackupHandler();
|
||||||
|
private PendingIntent mRunBackupIntent;
|
||||||
|
private BroadcastReceiver mRunBackupReceiver;
|
||||||
|
private IntentFilter mRunBackupFilter;
|
||||||
// map UIDs to the set of backup client services within that UID's app set
|
// map UIDs to the set of backup client services within that UID's app set
|
||||||
private final SparseArray<HashSet<ApplicationInfo>> mBackupParticipants
|
private final SparseArray<HashSet<ApplicationInfo>> mBackupParticipants
|
||||||
= new SparseArray<HashSet<ApplicationInfo>>();
|
= new SparseArray<HashSet<ApplicationInfo>>();
|
||||||
@ -171,12 +182,26 @@ class BackupManagerService extends IBackupManager.Stub {
|
|||||||
mPackageManager = context.getPackageManager();
|
mPackageManager = context.getPackageManager();
|
||||||
mActivityManager = ActivityManagerNative.getDefault();
|
mActivityManager = ActivityManagerNative.getDefault();
|
||||||
|
|
||||||
|
mAlarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
|
||||||
|
mPowerManager = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
|
||||||
|
|
||||||
// Set up our bookkeeping
|
// Set up our bookkeeping
|
||||||
mEnabled = Settings.Secure.getInt(context.getContentResolver(),
|
boolean areEnabled = Settings.Secure.getInt(context.getContentResolver(),
|
||||||
Settings.Secure.BACKUP_ENABLED, 0) != 0;
|
Settings.Secure.BACKUP_ENABLED, 0) != 0;
|
||||||
mBaseStateDir = new File(Environment.getDataDirectory(), "backup");
|
mBaseStateDir = new File(Environment.getDataDirectory(), "backup");
|
||||||
mDataDir = Environment.getDownloadCacheDirectory();
|
mDataDir = Environment.getDownloadCacheDirectory();
|
||||||
|
|
||||||
|
mRunBackupReceiver = new RunBackupReceiver();
|
||||||
|
mRunBackupFilter = new IntentFilter();
|
||||||
|
mRunBackupFilter.addAction(RUN_BACKUP_ACTION);
|
||||||
|
context.registerReceiver(mRunBackupReceiver, mRunBackupFilter);
|
||||||
|
|
||||||
|
Intent backupIntent = new Intent(RUN_BACKUP_ACTION);
|
||||||
|
// !!! TODO: restrict delivery to our receiver; the naive setClass() doesn't seem to work
|
||||||
|
//backupIntent.setClass(context, mRunBackupReceiver.getClass());
|
||||||
|
backupIntent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
|
||||||
|
mRunBackupIntent = PendingIntent.getBroadcast(context, MSG_RUN_BACKUP, backupIntent, 0);
|
||||||
|
|
||||||
// Set up the backup-request journaling
|
// Set up the backup-request journaling
|
||||||
mJournalDir = new File(mBaseStateDir, "pending");
|
mJournalDir = new File(mBaseStateDir, "pending");
|
||||||
mJournalDir.mkdirs(); // creates mBaseStateDir along the way
|
mJournalDir.mkdirs(); // creates mBaseStateDir along the way
|
||||||
@ -224,10 +249,27 @@ class BackupManagerService extends IBackupManager.Stub {
|
|||||||
filter.addDataScheme("package");
|
filter.addDataScheme("package");
|
||||||
mContext.registerReceiver(mBroadcastReceiver, filter);
|
mContext.registerReceiver(mBroadcastReceiver, filter);
|
||||||
|
|
||||||
// Schedule the first backup pass -- okay because no other threads are
|
// Power management
|
||||||
// running yet
|
mWakelock = mPowerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "backup");
|
||||||
if (mEnabled) {
|
|
||||||
scheduleBackupPassLocked(BACKUP_INTERVAL);
|
// Start the backup passes going
|
||||||
|
setBackupEnabled(areEnabled);
|
||||||
|
}
|
||||||
|
|
||||||
|
private class RunBackupReceiver extends BroadcastReceiver {
|
||||||
|
public void onReceive(Context context, Intent intent) {
|
||||||
|
if (RUN_BACKUP_ACTION.equals(intent.getAction())) {
|
||||||
|
if (DEBUG) Log.v(TAG, "Running a backup pass");
|
||||||
|
|
||||||
|
synchronized (mQueueLock) {
|
||||||
|
// acquire a wakelock and pass it to the backup thread. it will
|
||||||
|
// be released once backup concludes.
|
||||||
|
mWakelock.acquire();
|
||||||
|
|
||||||
|
Message msg = mBackupHandler.obtainMessage(MSG_RUN_BACKUP);
|
||||||
|
mBackupHandler.sendMessage(msg);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -344,6 +386,7 @@ class BackupManagerService extends IBackupManager.Stub {
|
|||||||
IBackupTransport transport = getTransport(mCurrentTransport);
|
IBackupTransport transport = getTransport(mCurrentTransport);
|
||||||
if (transport == null) {
|
if (transport == null) {
|
||||||
Log.v(TAG, "Backup requested but no transport available");
|
Log.v(TAG, "Backup requested but no transport available");
|
||||||
|
mWakelock.release();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -377,13 +420,9 @@ class BackupManagerService extends IBackupManager.Stub {
|
|||||||
(new PerformBackupThread(transport, queue, oldJournal)).start();
|
(new PerformBackupThread(transport, queue, oldJournal)).start();
|
||||||
} else {
|
} else {
|
||||||
Log.v(TAG, "Backup requested but nothing pending");
|
Log.v(TAG, "Backup requested but nothing pending");
|
||||||
|
mWakelock.release();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Schedule the next pass.
|
|
||||||
synchronized (mQueueLock) {
|
|
||||||
scheduleBackupPassLocked(BACKUP_INTERVAL);
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -394,7 +433,8 @@ class BackupManagerService extends IBackupManager.Stub {
|
|||||||
{
|
{
|
||||||
RestoreParams params = (RestoreParams)msg.obj;
|
RestoreParams params = (RestoreParams)msg.obj;
|
||||||
Log.d(TAG, "MSG_RUN_RESTORE observer=" + params.observer);
|
Log.d(TAG, "MSG_RUN_RESTORE observer=" + params.observer);
|
||||||
(new PerformRestoreThread(params.transport, params.observer, params.token)).start();
|
(new PerformRestoreThread(params.transport, params.observer,
|
||||||
|
params.token)).start();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -521,19 +561,6 @@ class BackupManagerService extends IBackupManager.Stub {
|
|||||||
addPackageParticipantsLockedInner(packageName, allApps);
|
addPackageParticipantsLockedInner(packageName, allApps);
|
||||||
}
|
}
|
||||||
|
|
||||||
// The queue lock should be held when scheduling a backup pass
|
|
||||||
private void scheduleBackupPassLocked(long timeFromNowMillis) {
|
|
||||||
// We only schedule backups when we're actually enabled
|
|
||||||
synchronized (this) {
|
|
||||||
if (mEnabled) {
|
|
||||||
mBackupHandler.removeMessages(MSG_RUN_BACKUP);
|
|
||||||
mBackupHandler.sendEmptyMessageDelayed(MSG_RUN_BACKUP, timeFromNowMillis);
|
|
||||||
} else if (DEBUG) {
|
|
||||||
Log.v(TAG, "Disabled, so not scheduling backup pass");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Return the given transport
|
// Return the given transport
|
||||||
private IBackupTransport getTransport(String transportName) {
|
private IBackupTransport getTransport(String transportName) {
|
||||||
synchronized (mTransports) {
|
synchronized (mTransports) {
|
||||||
@ -685,6 +712,9 @@ class BackupManagerService extends IBackupManager.Stub {
|
|||||||
if (!mJournal.delete()) {
|
if (!mJournal.delete()) {
|
||||||
Log.e(TAG, "Unable to remove backup journal file " + mJournal.getAbsolutePath());
|
Log.e(TAG, "Unable to remove backup journal file " + mJournal.getAbsolutePath());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Only once we're entirely finished do we release the wakelock
|
||||||
|
mWakelock.release();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void doQueuedBackups(IBackupTransport transport) {
|
private void doQueuedBackups(IBackupTransport transport) {
|
||||||
@ -1041,6 +1071,9 @@ class BackupManagerService extends IBackupManager.Stub {
|
|||||||
Log.d(TAG, "Restore observer died at restoreFinished");
|
Log.d(TAG, "Restore observer died at restoreFinished");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// done; we can finally release the wakelock
|
||||||
|
mWakelock.release();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1125,6 +1158,9 @@ class BackupManagerService extends IBackupManager.Stub {
|
|||||||
} catch (RemoteException e) {
|
} catch (RemoteException e) {
|
||||||
// can't happen; the transport is local
|
// can't happen; the transport is local
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Last but not least, release the cpu
|
||||||
|
mWakelock.release();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1237,6 +1273,7 @@ class BackupManagerService extends IBackupManager.Stub {
|
|||||||
if (DEBUG) Log.v(TAG, "Found the app - running clear process");
|
if (DEBUG) Log.v(TAG, "Found the app - running clear process");
|
||||||
// found it; fire off the clear request
|
// found it; fire off the clear request
|
||||||
synchronized (mQueueLock) {
|
synchronized (mQueueLock) {
|
||||||
|
mWakelock.acquire();
|
||||||
Message msg = mBackupHandler.obtainMessage(MSG_RUN_CLEAR,
|
Message msg = mBackupHandler.obtainMessage(MSG_RUN_CLEAR,
|
||||||
new ClearParams(getTransport(mCurrentTransport), info));
|
new ClearParams(getTransport(mCurrentTransport), info));
|
||||||
mBackupHandler.sendMessage(msg);
|
mBackupHandler.sendMessage(msg);
|
||||||
@ -1253,13 +1290,20 @@ class BackupManagerService extends IBackupManager.Stub {
|
|||||||
|
|
||||||
if (DEBUG) Log.v(TAG, "Scheduling immediate backup pass");
|
if (DEBUG) Log.v(TAG, "Scheduling immediate backup pass");
|
||||||
synchronized (mQueueLock) {
|
synchronized (mQueueLock) {
|
||||||
scheduleBackupPassLocked(0);
|
try {
|
||||||
|
if (DEBUG) Log.v(TAG, "sending immediate backup broadcast");
|
||||||
|
mRunBackupIntent.send();
|
||||||
|
} catch (PendingIntent.CanceledException e) {
|
||||||
|
// should never happen
|
||||||
|
Log.e(TAG, "run-backup intent cancelled!");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Enable/disable the backup transport
|
// Enable/disable the backup transport
|
||||||
public void setBackupEnabled(boolean enable) {
|
public void setBackupEnabled(boolean enable) {
|
||||||
mContext.enforceCallingPermission(android.Manifest.permission.BACKUP, "setBackupEnabled");
|
mContext.enforceCallingOrSelfPermission(android.Manifest.permission.BACKUP,
|
||||||
|
"setBackupEnabled");
|
||||||
|
|
||||||
boolean wasEnabled = mEnabled;
|
boolean wasEnabled = mEnabled;
|
||||||
synchronized (this) {
|
synchronized (this) {
|
||||||
@ -1271,10 +1315,12 @@ class BackupManagerService extends IBackupManager.Stub {
|
|||||||
synchronized (mQueueLock) {
|
synchronized (mQueueLock) {
|
||||||
if (enable && !wasEnabled) {
|
if (enable && !wasEnabled) {
|
||||||
// if we've just been enabled, start scheduling backup passes
|
// if we've just been enabled, start scheduling backup passes
|
||||||
scheduleBackupPassLocked(BACKUP_INTERVAL);
|
long when = System.currentTimeMillis() + BACKUP_INTERVAL;
|
||||||
|
mAlarmManager.setInexactRepeating(AlarmManager.RTC_WAKEUP, when,
|
||||||
|
BACKUP_INTERVAL, mRunBackupIntent);
|
||||||
} else if (!enable) {
|
} else if (!enable) {
|
||||||
// No longer enabled, so stop running backups.
|
// No longer enabled, so stop running backups
|
||||||
mBackupHandler.removeMessages(MSG_RUN_BACKUP);
|
mAlarmManager.cancel(mRunBackupIntent);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1422,6 +1468,7 @@ class BackupManagerService extends IBackupManager.Stub {
|
|||||||
if (mRestoreSets != null) {
|
if (mRestoreSets != null) {
|
||||||
for (int i = 0; i < mRestoreSets.length; i++) {
|
for (int i = 0; i < mRestoreSets.length; i++) {
|
||||||
if (token == mRestoreSets[i].token) {
|
if (token == mRestoreSets[i].token) {
|
||||||
|
mWakelock.acquire();
|
||||||
Message msg = mBackupHandler.obtainMessage(MSG_RUN_RESTORE);
|
Message msg = mBackupHandler.obtainMessage(MSG_RUN_RESTORE);
|
||||||
msg.obj = new RestoreParams(mRestoreTransport, observer, token);
|
msg.obj = new RestoreParams(mRestoreTransport, observer, token);
|
||||||
mBackupHandler.sendMessage(msg);
|
mBackupHandler.sendMessage(msg);
|
||||||
@ -1457,14 +1504,6 @@ class BackupManagerService extends IBackupManager.Stub {
|
|||||||
public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
|
public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
|
||||||
synchronized (mQueueLock) {
|
synchronized (mQueueLock) {
|
||||||
pw.println("Backup Manager is " + (mEnabled ? "enabled" : "disabled"));
|
pw.println("Backup Manager is " + (mEnabled ? "enabled" : "disabled"));
|
||||||
boolean scheduled = mBackupHandler.hasMessages(MSG_RUN_BACKUP);
|
|
||||||
if (scheduled != mEnabled) {
|
|
||||||
if (mEnabled) {
|
|
||||||
pw.println("ERROR: backups enabled but none scheduled!");
|
|
||||||
} else {
|
|
||||||
pw.println("ERROR: backups are scheduled but not enabled!");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
pw.println("Available transports:");
|
pw.println("Available transports:");
|
||||||
for (String t : listAllTransports()) {
|
for (String t : listAllTransports()) {
|
||||||
String pad = (t.equals(mCurrentTransport)) ? " * " : " ";
|
String pad = (t.equals(mCurrentTransport)) ? " * " : " ";
|
||||||
|
Reference in New Issue
Block a user