DO NOT MERGE Add stop method to backup handler thread.

am: 842369a82b

Change-Id: I42795aea1d5f31f04e65a66a8e78ce2431d90d3c
This commit is contained in:
nathch
2019-07-24 14:38:14 -07:00
committed by android-build-merger
7 changed files with 102 additions and 26 deletions

View File

@@ -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() {

View File

@@ -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) {

View File

@@ -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();

View File

@@ -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);

View File

@@ -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;

View File

@@ -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);

View File

@@ -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*"));
} }
/** /**