Introduce run-cleanup adb command for CTS test

1. Add "debug.cdm.cdmservice.removal_time_window" system property
2. Introduce the remove-inactive-associations  adb command
3. Check isSelfManaged instead of profile

Test: atest CtsCompanionDeviceManagerCoreTestCases
      atest CtsCompanionDeviceManagerUiAutomationTestCases
      atest CtsOsTestCases:CompanionDeviceManagerTest
Fix: 227798203
Change-Id: Id60c5c3d0e21736c5075c290a4324efa09ff04e8
This commit is contained in:
Evan Chen
2022-04-06 15:01:57 -07:00
parent abe0730018
commit 99c31fdd12
5 changed files with 56 additions and 38 deletions

View File

@@ -7044,7 +7044,7 @@
android:permission="android.permission.BIND_JOB_SERVICE">
</service>
<service android:name="com.android.server.companion.AssociationCleanUpService"
<service android:name="com.android.server.companion.InactiveAssociationsRemovalService"
android:permission="android.permission.BIND_JOB_SERVICE">
</service>

View File

@@ -78,6 +78,7 @@ import android.os.RemoteException;
import android.os.ResultReceiver;
import android.os.ServiceManager;
import android.os.ShellCallback;
import android.os.SystemProperties;
import android.os.UserHandle;
import android.os.UserManager;
import android.util.ArraySet;
@@ -121,8 +122,10 @@ public class CompanionDeviceManagerService extends SystemService {
private static final String PREF_FILE_NAME = "companion_device_preferences.xml";
private static final String PREF_KEY_AUTO_REVOKE_GRANTS_DONE = "auto_revoke_grants_done";
private static final String SYS_PROP_DEBUG_REMOVAL_TIME_WINDOW =
"debug.cdm.cdmservice.removal_time_window";
private static final long ASSOCIATION_CLEAN_UP_TIME_WINDOW = DAYS.toMillis(3 * 30); // 3 months
private static final long ASSOCIATION_REMOVAL_TIME_WINDOW_DEFAULT = DAYS.toMillis(90);
private PersistentDataStore mPersistentStore;
private final PersistUserStateHandler mUserPersistenceHandler;
@@ -211,8 +214,8 @@ public class CompanionDeviceManagerService extends SystemService {
mPackageMonitor.register(context, FgThread.get().getLooper(), UserHandle.ALL, true);
mDevicePresenceMonitor.init(context);
} else if (phase == PHASE_BOOT_COMPLETED) {
// Run the Association CleanUp job service daily.
AssociationCleanUpService.schedule(getContext());
// Run the Inactive Association Removal job service daily.
InactiveAssociationsRemovalService.schedule(getContext());
}
}
@@ -411,17 +414,20 @@ public class CompanionDeviceManagerService extends SystemService {
mCompanionAppController.onPackagesChanged(userId);
}
// Revoke associations if the selfManaged companion device does not connect for 3
// months for specific profile.
private void associationCleanUp(String profile) {
// Revoke associations if the selfManaged companion device does not connect for 3 months.
void removeInactiveSelfManagedAssociations() {
final long currentTime = System.currentTimeMillis();
long removalWindow = SystemProperties.getLong(SYS_PROP_DEBUG_REMOVAL_TIME_WINDOW, -1);
if (removalWindow <= 0) {
// 0 or negative values indicate that the sysprop was never set or should be ignored.
removalWindow = ASSOCIATION_REMOVAL_TIME_WINDOW_DEFAULT;
}
for (AssociationInfo ai : mAssociationStore.getAssociations()) {
if (ai.isSelfManaged()
&& profile.equals(ai.getDeviceProfile())
&& System.currentTimeMillis() - ai.getLastTimeConnectedMs()
>= ASSOCIATION_CLEAN_UP_TIME_WINDOW) {
Slog.i(TAG, "Removing the association for associationId: "
+ ai.getId()
+ " due to the device does not connect for 3 months.");
if (!ai.isSelfManaged()) continue;
final boolean isInactive = currentTime - ai.getLastTimeConnectedMs() >= removalWindow;
if (isInactive) {
Slog.i(TAG, "Removing inactive self-managed association: " + ai.getId());
disassociateInternal(ai.getId());
}
}
@@ -1057,10 +1063,10 @@ public class CompanionDeviceManagerService extends SystemService {
return ArrayUtils.contains(array, a) || ArrayUtils.contains(array, b);
}
private class LocalService extends CompanionDeviceManagerServiceInternal {
private class LocalService implements CompanionDeviceManagerServiceInternal {
@Override
public void associationCleanUp(String profile) {
CompanionDeviceManagerService.this.associationCleanUp(profile);
public void removeInactiveSelfManagedAssociations() {
CompanionDeviceManagerService.this.removeInactiveSelfManagedAssociations();
}
}

View File

@@ -18,12 +18,10 @@ package com.android.server.companion;
/**
* Companion Device Manager Local System Service Interface.
*
* @hide Only for use within the system server.
*/
public abstract class CompanionDeviceManagerServiceInternal {
interface CompanionDeviceManagerServiceInternal {
/**
* @see CompanionDeviceManagerService#associationCleanUp
* @see CompanionDeviceManagerService#removeInactiveSelfManagedAssociations
*/
public abstract void associationCleanUp(String profile);
void removeInactiveSelfManagedAssociations();
}

View File

@@ -17,6 +17,7 @@
package com.android.server.companion;
import android.companion.AssociationInfo;
import android.os.Binder;
import android.os.ShellCommand;
import android.util.Log;
import android.util.Slog;
@@ -96,6 +97,16 @@ class CompanionDeviceShellCommand extends ShellCommand {
mDevicePresenceMonitor.simulateDeviceDisappeared(associationId);
break;
case "remove-inactive-associations": {
// This command should trigger the same "clean-up" job as performed by the
// InactiveAssociationsRemovalService JobService. However, since the
// InactiveAssociationsRemovalService run as system, we want to run this
// as system (not as shell/root) as well.
Binder.withCleanCallingIdentity(
mService::removeInactiveSelfManagedAssociations);
}
break;
default:
return handleDefaultCommands(cmd);
}
@@ -142,6 +153,12 @@ class CompanionDeviceShellCommand extends ShellCommand {
pw.println(" invoked for the same device (same ASSOCIATION_ID) no longer than");
pw.println(" 60 seconds ago.");
pw.println(" USE FOR DEBUGGING AND/OR TESTING PURPOSES ONLY.");
pw.println(" remove-inactive-associations");
pw.println(" Remove self-managed associations that have not been active ");
pw.println(" for a long time (90 days or as configured via ");
pw.println(" \"debug.cdm.cdmservice.cleanup_time_window\" system property). ");
pw.println(" USE FOR DEBUGGING AND/OR TESTING PURPOSES ONLY.");
}
private int getNextIntArgRequired() {

View File

@@ -1,5 +1,5 @@
/*
* Copyright (C) 2021 The Android Open Source Project
* Copyright (C) 2022 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.
@@ -24,10 +24,8 @@ import android.app.job.JobInfo;
import android.app.job.JobParameters;
import android.app.job.JobScheduler;
import android.app.job.JobService;
import android.companion.AssociationRequest;
import android.content.ComponentName;
import android.content.Context;
import android.os.AsyncTask;
import android.util.Slog;
import com.android.server.LocalServices;
@@ -37,26 +35,24 @@ import com.android.server.LocalServices;
* The job will be executed only if the device is charging and in idle mode due to the application
* will be killed if association/role are revoked.
*/
public class AssociationCleanUpService extends JobService {
private static final int JOB_ID = AssociationCleanUpService.class.hashCode();
public class InactiveAssociationsRemovalService extends JobService {
private static final int JOB_ID = InactiveAssociationsRemovalService.class.hashCode();
private static final long ONE_DAY_INTERVAL = DAYS.toMillis(1);
@Override
public boolean onStartJob(final JobParameters params) {
Slog.i(TAG, "Execute the Association CleanUp job");
// Special policy for APP_STREAMING role that need to revoke associations if the device
// does not connect for 3 months.
AsyncTask.execute(() -> {
LocalServices.getService(CompanionDeviceManagerServiceInternal.class)
.associationCleanUp(AssociationRequest.DEVICE_PROFILE_APP_STREAMING);
jobFinished(params, false);
});
Slog.i(TAG, "Execute the Association Removal job");
// Special policy for selfManaged that need to revoke associations if the device
// does not connect for 90 days.
LocalServices.getService(CompanionDeviceManagerServiceInternal.class)
.removeInactiveSelfManagedAssociations();
jobFinished(params, false);
return true;
}
@Override
public boolean onStopJob(final JobParameters params) {
Slog.i(TAG, "Association cleanup job stopped; id=" + params.getJobId()
Slog.i(TAG, "Association removal job stopped; id=" + params.getJobId()
+ ", reason="
+ JobParameters.getInternalReasonCodeDescription(
params.getInternalStopReasonCode()));
@@ -64,10 +60,10 @@ public class AssociationCleanUpService extends JobService {
}
static void schedule(Context context) {
Slog.i(TAG, "Scheduling the Association Cleanup job");
Slog.i(TAG, "Scheduling the Association Removal job");
final JobScheduler jobScheduler = context.getSystemService(JobScheduler.class);
final JobInfo job = new JobInfo.Builder(JOB_ID,
new ComponentName(context, AssociationCleanUpService.class))
new ComponentName(context, InactiveAssociationsRemovalService.class))
.setRequiresCharging(true)
.setRequiresDeviceIdle(true)
.setPeriodic(ONE_DAY_INTERVAL)
@@ -75,3 +71,4 @@ public class AssociationCleanUpService extends JobService {
jobScheduler.schedule(job);
}
}