DO NOT MERGE Add stop method to backup handler thread.
am: 842369a82b
Change-Id: I42795aea1d5f31f04e65a66a8e78ce2431d90d3c
This commit is contained in:
@@ -166,6 +166,52 @@ import java.util.concurrent.atomic.AtomicInteger;
|
|||||||
|
|
||||||
/** System service that performs backup/restore operations. */
|
/** System service that performs backup/restore operations. */
|
||||||
public class UserBackupManagerService {
|
public class UserBackupManagerService {
|
||||||
|
/** Wrapper over {@link PowerManager.WakeLock} to prevent double-free exceptions on release()
|
||||||
|
* after quit().
|
||||||
|
* */
|
||||||
|
public static class BackupWakeLock {
|
||||||
|
private final PowerManager.WakeLock mPowerManagerWakeLock;
|
||||||
|
private boolean mHasQuit = false;
|
||||||
|
|
||||||
|
public BackupWakeLock(PowerManager.WakeLock powerManagerWakeLock) {
|
||||||
|
mPowerManagerWakeLock = powerManagerWakeLock;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Acquires the {@link PowerManager.WakeLock} if hasn't been quit. */
|
||||||
|
public synchronized void acquire() {
|
||||||
|
if (mHasQuit) {
|
||||||
|
Slog.v(TAG, "Ignore wakelock acquire after quit:" + mPowerManagerWakeLock.getTag());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
mPowerManagerWakeLock.acquire();
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Releases the {@link PowerManager.WakeLock} if hasn't been quit. */
|
||||||
|
public synchronized void release() {
|
||||||
|
if (mHasQuit) {
|
||||||
|
Slog.v(TAG, "Ignore wakelock release after quit:" + mPowerManagerWakeLock.getTag());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
mPowerManagerWakeLock.release();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns true if the {@link PowerManager.WakeLock} has been acquired but not yet released.
|
||||||
|
*/
|
||||||
|
public synchronized boolean isHeld() {
|
||||||
|
return mPowerManagerWakeLock.isHeld();
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Release the {@link PowerManager.WakeLock} till it isn't held. */
|
||||||
|
public synchronized void quit() {
|
||||||
|
while (mPowerManagerWakeLock.isHeld()) {
|
||||||
|
Slog.v(TAG, "Releasing wakelock:" + mPowerManagerWakeLock.getTag());
|
||||||
|
mPowerManagerWakeLock.release();
|
||||||
|
}
|
||||||
|
mHasQuit = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Persistently track the need to do a full init.
|
// Persistently track the need to do a full init.
|
||||||
private static final String INIT_SENTINEL_FILE_NAME = "_need_init_";
|
private static final String INIT_SENTINEL_FILE_NAME = "_need_init_";
|
||||||
|
|
||||||
@@ -252,7 +298,6 @@ public class UserBackupManagerService {
|
|||||||
private final @UserIdInt int mUserId;
|
private final @UserIdInt int mUserId;
|
||||||
private final BackupAgentTimeoutParameters mAgentTimeoutParameters;
|
private final BackupAgentTimeoutParameters mAgentTimeoutParameters;
|
||||||
private final TransportManager mTransportManager;
|
private final TransportManager mTransportManager;
|
||||||
private final HandlerThread mUserBackupThread;
|
|
||||||
|
|
||||||
private final Context mContext;
|
private final Context mContext;
|
||||||
private final PackageManager mPackageManager;
|
private final PackageManager mPackageManager;
|
||||||
@@ -263,7 +308,7 @@ public class UserBackupManagerService {
|
|||||||
private final AlarmManager mAlarmManager;
|
private final AlarmManager mAlarmManager;
|
||||||
private final IStorageManager mStorageManager;
|
private final IStorageManager mStorageManager;
|
||||||
private final BackupManagerConstants mConstants;
|
private final BackupManagerConstants mConstants;
|
||||||
private final PowerManager.WakeLock mWakelock;
|
private final BackupWakeLock mWakelock;
|
||||||
private final BackupHandler mBackupHandler;
|
private final BackupHandler mBackupHandler;
|
||||||
|
|
||||||
private final IBackupManager mBackupManagerBinder;
|
private final IBackupManager mBackupManagerBinder;
|
||||||
@@ -487,8 +532,7 @@ public class UserBackupManagerService {
|
|||||||
mAgentTimeoutParameters.start();
|
mAgentTimeoutParameters.start();
|
||||||
|
|
||||||
checkNotNull(userBackupThread, "userBackupThread cannot be null");
|
checkNotNull(userBackupThread, "userBackupThread cannot be null");
|
||||||
mUserBackupThread = userBackupThread;
|
mBackupHandler = new BackupHandler(this, userBackupThread);
|
||||||
mBackupHandler = new BackupHandler(this, userBackupThread.getLooper());
|
|
||||||
|
|
||||||
// Set up our bookkeeping
|
// Set up our bookkeeping
|
||||||
final ContentResolver resolver = context.getContentResolver();
|
final ContentResolver resolver = context.getContentResolver();
|
||||||
@@ -588,7 +632,10 @@ public class UserBackupManagerService {
|
|||||||
mBackupHandler.postDelayed(this::parseLeftoverJournals, INITIALIZATION_DELAY_MILLIS);
|
mBackupHandler.postDelayed(this::parseLeftoverJournals, INITIALIZATION_DELAY_MILLIS);
|
||||||
|
|
||||||
// Power management
|
// Power management
|
||||||
mWakelock = mPowerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "*backup*-" + userId);
|
mWakelock = new BackupWakeLock(
|
||||||
|
mPowerManager.newWakeLock(
|
||||||
|
PowerManager.PARTIAL_WAKE_LOCK,
|
||||||
|
"*backup*-" + userId + "-" + userBackupThread.getThreadId()));
|
||||||
|
|
||||||
// Set up the various sorts of package tracking we do
|
// Set up the various sorts of package tracking we do
|
||||||
mFullBackupScheduleFile = new File(mBaseStateDir, "fb-schedule");
|
mFullBackupScheduleFile = new File(mBaseStateDir, "fb-schedule");
|
||||||
@@ -608,7 +655,7 @@ public class UserBackupManagerService {
|
|||||||
mContext.unregisterReceiver(mRunBackupReceiver);
|
mContext.unregisterReceiver(mRunBackupReceiver);
|
||||||
mContext.unregisterReceiver(mRunInitReceiver);
|
mContext.unregisterReceiver(mRunInitReceiver);
|
||||||
mContext.unregisterReceiver(mPackageTrackingReceiver);
|
mContext.unregisterReceiver(mPackageTrackingReceiver);
|
||||||
mUserBackupThread.quit();
|
mBackupHandler.stop();
|
||||||
}
|
}
|
||||||
|
|
||||||
public @UserIdInt int getUserId() {
|
public @UserIdInt int getUserId() {
|
||||||
@@ -668,7 +715,7 @@ public class UserBackupManagerService {
|
|||||||
mSetupComplete = setupComplete;
|
mSetupComplete = setupComplete;
|
||||||
}
|
}
|
||||||
|
|
||||||
public PowerManager.WakeLock getWakelock() {
|
public BackupWakeLock getWakelock() {
|
||||||
return mWakelock;
|
return mWakelock;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -679,7 +726,7 @@ public class UserBackupManagerService {
|
|||||||
@VisibleForTesting
|
@VisibleForTesting
|
||||||
public void setWorkSource(@Nullable WorkSource workSource) {
|
public void setWorkSource(@Nullable WorkSource workSource) {
|
||||||
// TODO: This is for testing, unfortunately WakeLock is final and WorkSource is not exposed
|
// TODO: This is for testing, unfortunately WakeLock is final and WorkSource is not exposed
|
||||||
mWakelock.setWorkSource(workSource);
|
mWakelock.mPowerManagerWakeLock.setWorkSource(workSource);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Handler getBackupHandler() {
|
public Handler getBackupHandler() {
|
||||||
|
|||||||
@@ -23,7 +23,7 @@ import static com.android.server.backup.BackupManagerService.TAG;
|
|||||||
import android.app.backup.RestoreSet;
|
import android.app.backup.RestoreSet;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.os.Handler;
|
import android.os.Handler;
|
||||||
import android.os.Looper;
|
import android.os.HandlerThread;
|
||||||
import android.os.Message;
|
import android.os.Message;
|
||||||
import android.os.RemoteException;
|
import android.os.RemoteException;
|
||||||
import android.os.UserHandle;
|
import android.os.UserHandle;
|
||||||
@@ -83,19 +83,47 @@ public class BackupHandler extends Handler {
|
|||||||
// backup task state machine tick
|
// backup task state machine tick
|
||||||
public static final int MSG_BACKUP_RESTORE_STEP = 20;
|
public static final int MSG_BACKUP_RESTORE_STEP = 20;
|
||||||
public static final int MSG_OP_COMPLETE = 21;
|
public static final int MSG_OP_COMPLETE = 21;
|
||||||
|
// Release the wakelock. This is used to ensure we don't hold it after
|
||||||
|
// a user is removed. This will also terminate the looper thread.
|
||||||
|
public static final int MSG_STOP = 22;
|
||||||
|
|
||||||
private final UserBackupManagerService backupManagerService;
|
private final UserBackupManagerService backupManagerService;
|
||||||
private final BackupAgentTimeoutParameters mAgentTimeoutParameters;
|
private final BackupAgentTimeoutParameters mAgentTimeoutParameters;
|
||||||
|
|
||||||
public BackupHandler(UserBackupManagerService backupManagerService, Looper looper) {
|
private final HandlerThread mBackupThread;
|
||||||
super(looper);
|
private volatile boolean mIsStopping = false;
|
||||||
|
|
||||||
|
public BackupHandler(
|
||||||
|
UserBackupManagerService backupManagerService, HandlerThread backupThread) {
|
||||||
|
super(backupThread.getLooper());
|
||||||
|
mBackupThread = backupThread;
|
||||||
this.backupManagerService = backupManagerService;
|
this.backupManagerService = backupManagerService;
|
||||||
mAgentTimeoutParameters = Preconditions.checkNotNull(
|
mAgentTimeoutParameters = Preconditions.checkNotNull(
|
||||||
backupManagerService.getAgentTimeoutParameters(),
|
backupManagerService.getAgentTimeoutParameters(),
|
||||||
"Timeout parameters cannot be null");
|
"Timeout parameters cannot be null");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Put the BackupHandler into a stopping state where the remaining messages on the queue will be
|
||||||
|
* silently dropped and the {@link WakeLock} held by the {@link UserBackupManagerService} will
|
||||||
|
* then be released.
|
||||||
|
*/
|
||||||
|
public void stop() {
|
||||||
|
mIsStopping = true;
|
||||||
|
sendMessage(obtainMessage(BackupHandler.MSG_STOP));
|
||||||
|
}
|
||||||
|
|
||||||
public void handleMessage(Message msg) {
|
public void handleMessage(Message msg) {
|
||||||
|
if (msg.what == MSG_STOP) {
|
||||||
|
Slog.v(TAG, "Stopping backup handler");
|
||||||
|
backupManagerService.getWakelock().quit();
|
||||||
|
mBackupThread.quitSafely();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mIsStopping) {
|
||||||
|
// If we're finishing all other types of messages should be ignored
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
TransportManager transportManager = backupManagerService.getTransportManager();
|
TransportManager transportManager = backupManagerService.getTransportManager();
|
||||||
switch (msg.what) {
|
switch (msg.what) {
|
||||||
|
|||||||
@@ -23,7 +23,6 @@ import static com.android.server.backup.UserBackupManagerService.RUN_INITIALIZE_
|
|||||||
import android.content.BroadcastReceiver;
|
import android.content.BroadcastReceiver;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.os.PowerManager;
|
|
||||||
import android.util.Slog;
|
import android.util.Slog;
|
||||||
|
|
||||||
import com.android.server.backup.UserBackupManagerService;
|
import com.android.server.backup.UserBackupManagerService;
|
||||||
@@ -57,7 +56,8 @@ public class RunInitializeReceiver extends BroadcastReceiver {
|
|||||||
|
|
||||||
mUserBackupManagerService.clearPendingInits();
|
mUserBackupManagerService.clearPendingInits();
|
||||||
|
|
||||||
PowerManager.WakeLock wakelock = mUserBackupManagerService.getWakelock();
|
UserBackupManagerService.BackupWakeLock wakelock =
|
||||||
|
mUserBackupManagerService.getWakelock();
|
||||||
wakelock.acquire();
|
wakelock.acquire();
|
||||||
OnTaskFinishedListener listener = caller -> wakelock.release();
|
OnTaskFinishedListener listener = caller -> wakelock.release();
|
||||||
|
|
||||||
|
|||||||
@@ -34,7 +34,6 @@ import android.content.pm.PackageManager.NameNotFoundException;
|
|||||||
import android.os.Binder;
|
import android.os.Binder;
|
||||||
import android.os.Handler;
|
import android.os.Handler;
|
||||||
import android.os.Message;
|
import android.os.Message;
|
||||||
import android.os.PowerManager;
|
|
||||||
import android.util.Slog;
|
import android.util.Slog;
|
||||||
|
|
||||||
import com.android.server.backup.TransportManager;
|
import com.android.server.backup.TransportManager;
|
||||||
@@ -110,7 +109,7 @@ public class ActiveRestoreSession extends IRestoreSession.Stub {
|
|||||||
// comes in.
|
// comes in.
|
||||||
mBackupManagerService.getBackupHandler().removeMessages(MSG_RESTORE_SESSION_TIMEOUT);
|
mBackupManagerService.getBackupHandler().removeMessages(MSG_RESTORE_SESSION_TIMEOUT);
|
||||||
|
|
||||||
PowerManager.WakeLock wakelock = mBackupManagerService.getWakelock();
|
UserBackupManagerService.BackupWakeLock wakelock = mBackupManagerService.getWakelock();
|
||||||
wakelock.acquire();
|
wakelock.acquire();
|
||||||
|
|
||||||
// Prevent lambda from leaking 'this'
|
// Prevent lambda from leaking 'this'
|
||||||
@@ -392,7 +391,7 @@ public class ActiveRestoreSession extends IRestoreSession.Stub {
|
|||||||
Handler backupHandler = mBackupManagerService.getBackupHandler();
|
Handler backupHandler = mBackupManagerService.getBackupHandler();
|
||||||
backupHandler.removeMessages(MSG_RESTORE_SESSION_TIMEOUT);
|
backupHandler.removeMessages(MSG_RESTORE_SESSION_TIMEOUT);
|
||||||
|
|
||||||
PowerManager.WakeLock wakelock = mBackupManagerService.getWakelock();
|
UserBackupManagerService.BackupWakeLock wakelock = mBackupManagerService.getWakelock();
|
||||||
wakelock.acquire();
|
wakelock.acquire();
|
||||||
if (MORE_DEBUG) {
|
if (MORE_DEBUG) {
|
||||||
Slog.d(TAG, callerLogString);
|
Slog.d(TAG, callerLogString);
|
||||||
|
|||||||
@@ -94,7 +94,6 @@ import android.os.Handler;
|
|||||||
import android.os.Looper;
|
import android.os.Looper;
|
||||||
import android.os.Message;
|
import android.os.Message;
|
||||||
import android.os.ParcelFileDescriptor;
|
import android.os.ParcelFileDescriptor;
|
||||||
import android.os.PowerManager;
|
|
||||||
import android.os.RemoteException;
|
import android.os.RemoteException;
|
||||||
import android.platform.test.annotations.Presubmit;
|
import android.platform.test.annotations.Presubmit;
|
||||||
import android.util.Pair;
|
import android.util.Pair;
|
||||||
@@ -184,7 +183,7 @@ public class KeyValueBackupTaskTest {
|
|||||||
private TransportData mTransport;
|
private TransportData mTransport;
|
||||||
private ShadowLooper mShadowBackupLooper;
|
private ShadowLooper mShadowBackupLooper;
|
||||||
private Handler mBackupHandler;
|
private Handler mBackupHandler;
|
||||||
private PowerManager.WakeLock mWakeLock;
|
private UserBackupManagerService.BackupWakeLock mWakeLock;
|
||||||
private KeyValueBackupReporter mReporter;
|
private KeyValueBackupReporter mReporter;
|
||||||
private PackageManager mPackageManager;
|
private PackageManager mPackageManager;
|
||||||
private ShadowPackageManager mShadowPackageManager;
|
private ShadowPackageManager mShadowPackageManager;
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ package com.android.server.backup.restore;
|
|||||||
|
|
||||||
import static com.android.server.backup.testing.BackupManagerServiceTestUtils.createBackupWakeLock;
|
import static com.android.server.backup.testing.BackupManagerServiceTestUtils.createBackupWakeLock;
|
||||||
import static com.android.server.backup.testing.BackupManagerServiceTestUtils.setUpBackupManagerServiceBasics;
|
import static com.android.server.backup.testing.BackupManagerServiceTestUtils.setUpBackupManagerServiceBasics;
|
||||||
import static com.android.server.backup.testing.BackupManagerServiceTestUtils.startBackupThreadAndGetLooper;
|
import static com.android.server.backup.testing.BackupManagerServiceTestUtils.startBackupThread;
|
||||||
import static com.android.server.backup.testing.TestUtils.assertEventLogged;
|
import static com.android.server.backup.testing.TestUtils.assertEventLogged;
|
||||||
import static com.android.server.backup.testing.TestUtils.assertEventNotLogged;
|
import static com.android.server.backup.testing.TestUtils.assertEventNotLogged;
|
||||||
import static com.android.server.backup.testing.TransportData.backupTransport;
|
import static com.android.server.backup.testing.TransportData.backupTransport;
|
||||||
@@ -44,8 +44,8 @@ import android.app.backup.RestoreSet;
|
|||||||
import android.content.pm.ApplicationInfo;
|
import android.content.pm.ApplicationInfo;
|
||||||
import android.content.pm.PackageInfo;
|
import android.content.pm.PackageInfo;
|
||||||
import android.os.Handler;
|
import android.os.Handler;
|
||||||
|
import android.os.HandlerThread;
|
||||||
import android.os.Looper;
|
import android.os.Looper;
|
||||||
import android.os.PowerManager;
|
|
||||||
import android.os.RemoteException;
|
import android.os.RemoteException;
|
||||||
import android.platform.test.annotations.Presubmit;
|
import android.platform.test.annotations.Presubmit;
|
||||||
|
|
||||||
@@ -98,7 +98,7 @@ public class ActiveRestoreSessionTest {
|
|||||||
@Mock private IBackupManagerMonitor mMonitor;
|
@Mock private IBackupManagerMonitor mMonitor;
|
||||||
private ShadowLooper mShadowBackupLooper;
|
private ShadowLooper mShadowBackupLooper;
|
||||||
private ShadowApplication mShadowApplication;
|
private ShadowApplication mShadowApplication;
|
||||||
private PowerManager.WakeLock mWakeLock;
|
private UserBackupManagerService.BackupWakeLock mWakeLock;
|
||||||
private TransportData mTransport;
|
private TransportData mTransport;
|
||||||
private RestoreSet mRestoreSet1;
|
private RestoreSet mRestoreSet1;
|
||||||
private RestoreSet mRestoreSet2;
|
private RestoreSet mRestoreSet2;
|
||||||
@@ -118,7 +118,8 @@ public class ActiveRestoreSessionTest {
|
|||||||
|
|
||||||
mShadowPackageManager = shadowOf(application.getPackageManager());
|
mShadowPackageManager = shadowOf(application.getPackageManager());
|
||||||
|
|
||||||
Looper backupLooper = startBackupThreadAndGetLooper();
|
HandlerThread handlerThread = startBackupThread(null);
|
||||||
|
Looper backupLooper = handlerThread.getLooper();
|
||||||
mShadowBackupLooper = shadowOf(backupLooper);
|
mShadowBackupLooper = shadowOf(backupLooper);
|
||||||
|
|
||||||
Handler mainHandler = new Handler(Looper.getMainLooper());
|
Handler mainHandler = new Handler(Looper.getMainLooper());
|
||||||
@@ -129,7 +130,7 @@ public class ActiveRestoreSessionTest {
|
|||||||
// We need to mock BMS timeout parameters before initializing the BackupHandler since
|
// We need to mock BMS timeout parameters before initializing the BackupHandler since
|
||||||
// the constructor of BackupHandler relies on it.
|
// the constructor of BackupHandler relies on it.
|
||||||
when(mBackupManagerService.getAgentTimeoutParameters()).thenReturn(agentTimeoutParameters);
|
when(mBackupManagerService.getAgentTimeoutParameters()).thenReturn(agentTimeoutParameters);
|
||||||
BackupHandler backupHandler = new BackupHandler(mBackupManagerService, backupLooper);
|
BackupHandler backupHandler = new BackupHandler(mBackupManagerService, handlerThread);
|
||||||
|
|
||||||
mWakeLock = createBackupWakeLock(application);
|
mWakeLock = createBackupWakeLock(application);
|
||||||
|
|
||||||
|
|||||||
@@ -113,7 +113,7 @@ public class BackupManagerServiceTestUtils {
|
|||||||
TransportManager transportManager,
|
TransportManager transportManager,
|
||||||
PackageManager packageManager,
|
PackageManager packageManager,
|
||||||
Handler backupHandler,
|
Handler backupHandler,
|
||||||
PowerManager.WakeLock wakeLock,
|
UserBackupManagerService.BackupWakeLock wakeLock,
|
||||||
BackupAgentTimeoutParameters agentTimeoutParameters) {
|
BackupAgentTimeoutParameters agentTimeoutParameters) {
|
||||||
|
|
||||||
when(backupManagerService.getContext()).thenReturn(application);
|
when(backupManagerService.getContext()).thenReturn(application);
|
||||||
@@ -161,10 +161,12 @@ public class BackupManagerServiceTestUtils {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public static PowerManager.WakeLock createBackupWakeLock(Application application) {
|
public static UserBackupManagerService.BackupWakeLock createBackupWakeLock(
|
||||||
|
Application application) {
|
||||||
PowerManager powerManager =
|
PowerManager powerManager =
|
||||||
(PowerManager) application.getSystemService(Context.POWER_SERVICE);
|
(PowerManager) application.getSystemService(Context.POWER_SERVICE);
|
||||||
return powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "*backup*");
|
return new UserBackupManagerService.BackupWakeLock(
|
||||||
|
powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "*backup*"));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
Reference in New Issue
Block a user