Loading core/res/AndroidManifest.xml +1 −1 Original line number Diff line number Diff line Loading @@ -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> Loading services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java +22 −16 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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; Loading Loading @@ -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()); } } Loading Loading @@ -410,17 +413,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()); } } Loading Loading @@ -1078,10 +1084,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(); } } Loading services/companion/java/com/android/server/companion/CompanionDeviceManagerServiceInternal.java +3 −5 Original line number Diff line number Diff line Loading @@ -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(); } services/companion/java/com/android/server/companion/CompanionDeviceShellCommand.java +17 −0 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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); } Loading Loading @@ -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() { Loading services/companion/java/com/android/server/companion/AssociationCleanUpService.java→services/companion/java/com/android/server/companion/InactiveAssociationsRemovalService.java +13 −16 Original line number Diff line number Diff line /* * 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. Loading @@ -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; Loading @@ -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(() -> { 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) .associationCleanUp(AssociationRequest.DEVICE_PROFILE_APP_STREAMING); .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())); Loading @@ -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) Loading @@ -75,3 +71,4 @@ public class AssociationCleanUpService extends JobService { jobScheduler.schedule(job); } } Loading
core/res/AndroidManifest.xml +1 −1 Original line number Diff line number Diff line Loading @@ -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> Loading
services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java +22 −16 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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; Loading Loading @@ -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()); } } Loading Loading @@ -410,17 +413,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()); } } Loading Loading @@ -1078,10 +1084,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(); } } Loading
services/companion/java/com/android/server/companion/CompanionDeviceManagerServiceInternal.java +3 −5 Original line number Diff line number Diff line Loading @@ -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(); }
services/companion/java/com/android/server/companion/CompanionDeviceShellCommand.java +17 −0 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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); } Loading Loading @@ -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() { Loading
services/companion/java/com/android/server/companion/AssociationCleanUpService.java→services/companion/java/com/android/server/companion/InactiveAssociationsRemovalService.java +13 −16 Original line number Diff line number Diff line /* * 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. Loading @@ -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; Loading @@ -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(() -> { 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) .associationCleanUp(AssociationRequest.DEVICE_PROFILE_APP_STREAMING); .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())); Loading @@ -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) Loading @@ -75,3 +71,4 @@ public class AssociationCleanUpService extends JobService { jobScheduler.schedule(job); } }