Replace inexact alarm setRepeasting with setExact alarm

Use exact alarm to fix entilement recheck delay problem while device
asleep.

Bug: 195370891
Test: atest TehteringTests
Change-Id: I409e603bf2b990657551e1140b50f69640c328d8
This commit is contained in:
markchien
2021-08-12 13:29:17 +08:00
parent 73745baa38
commit 52158b1d47
2 changed files with 69 additions and 10 deletions

View File

@@ -70,7 +70,8 @@ public class EntitlementManager {
@VisibleForTesting @VisibleForTesting
protected static final String DISABLE_PROVISIONING_SYSPROP_KEY = "net.tethering.noprovisioning"; protected static final String DISABLE_PROVISIONING_SYSPROP_KEY = "net.tethering.noprovisioning";
private static final String ACTION_PROVISIONING_ALARM = @VisibleForTesting
protected static final String ACTION_PROVISIONING_ALARM =
"com.android.networkstack.tethering.PROVISIONING_RECHECK_ALARM"; "com.android.networkstack.tethering.PROVISIONING_RECHECK_ALARM";
private final ComponentName mSilentProvisioningService; private final ComponentName mSilentProvisioningService;
@@ -410,20 +411,23 @@ public class EntitlementManager {
return intent; return intent;
} }
@VisibleForTesting
PendingIntent createRecheckAlarmIntent() {
final Intent intent = new Intent(ACTION_PROVISIONING_ALARM);
return PendingIntent.getBroadcast(mContext, 0, intent, PendingIntent.FLAG_IMMUTABLE);
}
// Not needed to check if this don't run on the handler thread because it's private. // Not needed to check if this don't run on the handler thread because it's private.
private void scheduleProvisioningRechecks(final TetheringConfiguration config) { private void scheduleProvisioningRecheck(final TetheringConfiguration config) {
if (mProvisioningRecheckAlarm == null) { if (mProvisioningRecheckAlarm == null) {
final int period = config.provisioningCheckPeriod; final int period = config.provisioningCheckPeriod;
if (period <= 0) return; if (period <= 0) return;
Intent intent = new Intent(ACTION_PROVISIONING_ALARM); mProvisioningRecheckAlarm = createRecheckAlarmIntent();
mProvisioningRecheckAlarm = PendingIntent.getBroadcast(mContext, 0, intent,
PendingIntent.FLAG_IMMUTABLE);
AlarmManager alarmManager = (AlarmManager) mContext.getSystemService( AlarmManager alarmManager = (AlarmManager) mContext.getSystemService(
Context.ALARM_SERVICE); Context.ALARM_SERVICE);
long periodMs = period * MS_PER_HOUR; long triggerAtMillis = SystemClock.elapsedRealtime() + (period * MS_PER_HOUR);
long firstAlarmTime = SystemClock.elapsedRealtime() + periodMs; alarmManager.setExact(AlarmManager.ELAPSED_REALTIME_WAKEUP, triggerAtMillis,
alarmManager.setRepeating(AlarmManager.ELAPSED_REALTIME, firstAlarmTime, periodMs,
mProvisioningRecheckAlarm); mProvisioningRecheckAlarm);
} }
} }
@@ -437,6 +441,11 @@ public class EntitlementManager {
} }
} }
private void rescheduleProvisioningRecheck(final TetheringConfiguration config) {
cancelTetherProvisioningRechecks();
scheduleProvisioningRecheck(config);
}
private void evaluateCellularPermission(final TetheringConfiguration config) { private void evaluateCellularPermission(final TetheringConfiguration config) {
final boolean permitted = isCellularUpstreamPermitted(config); final boolean permitted = isCellularUpstreamPermitted(config);
@@ -452,7 +461,7 @@ public class EntitlementManager {
// Only schedule periodic re-check when tether is provisioned // Only schedule periodic re-check when tether is provisioned
// and the result is ok. // and the result is ok.
if (permitted && mCurrentEntitlementResults.size() > 0) { if (permitted && mCurrentEntitlementResults.size() > 0) {
scheduleProvisioningRechecks(config); scheduleProvisioningRecheck(config);
} else { } else {
cancelTetherProvisioningRechecks(); cancelTetherProvisioningRechecks();
} }
@@ -493,6 +502,7 @@ public class EntitlementManager {
if (ACTION_PROVISIONING_ALARM.equals(intent.getAction())) { if (ACTION_PROVISIONING_ALARM.equals(intent.getAction())) {
mLog.log("Received provisioning alarm"); mLog.log("Received provisioning alarm");
final TetheringConfiguration config = mFetcher.fetchTetheringConfiguration(); final TetheringConfiguration config = mFetcher.fetchTetheringConfiguration();
rescheduleProvisioningRecheck(config);
reevaluateSimCardProvisioning(config); reevaluateSimCardProvisioning(config);
} }
} }

View File

@@ -43,14 +43,18 @@ import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue; import static org.junit.Assert.assertTrue;
import static org.mockito.Matchers.anyBoolean; import static org.mockito.Matchers.anyBoolean;
import static org.mockito.Matchers.anyInt; import static org.mockito.Matchers.anyInt;
import static org.mockito.Matchers.anyLong;
import static org.mockito.Matchers.anyString; import static org.mockito.Matchers.anyString;
import static org.mockito.Matchers.eq; import static org.mockito.Matchers.eq;
import static org.mockito.Mockito.inOrder; import static org.mockito.Mockito.inOrder;
import static org.mockito.Mockito.reset;
import static org.mockito.Mockito.spy; import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.times; import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify; import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when; import static org.mockito.Mockito.when;
import android.app.AlarmManager;
import android.app.PendingIntent;
import android.content.Context; import android.content.Context;
import android.content.Intent; import android.content.Intent;
import android.content.pm.ModuleInfo; import android.content.pm.ModuleInfo;
@@ -63,6 +67,7 @@ import android.os.Handler;
import android.os.PersistableBundle; import android.os.PersistableBundle;
import android.os.ResultReceiver; import android.os.ResultReceiver;
import android.os.SystemProperties; import android.os.SystemProperties;
import android.os.UserHandle;
import android.os.test.TestLooper; import android.os.test.TestLooper;
import android.provider.DeviceConfig; import android.provider.DeviceConfig;
import android.provider.Settings; import android.provider.Settings;
@@ -91,6 +96,7 @@ public final class EntitlementManagerTest {
private static final String PROVISIONING_NO_UI_APP_NAME = "no_ui_app"; private static final String PROVISIONING_NO_UI_APP_NAME = "no_ui_app";
private static final String PROVISIONING_APP_RESPONSE = "app_response"; private static final String PROVISIONING_APP_RESPONSE = "app_response";
private static final String TEST_PACKAGE_NAME = "com.android.tethering.test"; private static final String TEST_PACKAGE_NAME = "com.android.tethering.test";
private static final int RECHECK_TIMER_HOURS = 24;
@Mock private CarrierConfigManager mCarrierConfigManager; @Mock private CarrierConfigManager mCarrierConfigManager;
@Mock private Context mContext; @Mock private Context mContext;
@@ -98,12 +104,14 @@ public final class EntitlementManagerTest {
@Mock private SharedLog mLog; @Mock private SharedLog mLog;
@Mock private PackageManager mPm; @Mock private PackageManager mPm;
@Mock private EntitlementManager.OnUiEntitlementFailedListener mEntitlementFailedListener; @Mock private EntitlementManager.OnUiEntitlementFailedListener mEntitlementFailedListener;
@Mock private AlarmManager mAlarmManager;
@Mock private PendingIntent mAlarmIntent;
// Like so many Android system APIs, these cannot be mocked because it is marked final. // Like so many Android system APIs, these cannot be mocked because it is marked final.
// We have to use the real versions. // We have to use the real versions.
private final PersistableBundle mCarrierConfig = new PersistableBundle(); private final PersistableBundle mCarrierConfig = new PersistableBundle();
private final TestLooper mLooper = new TestLooper(); private final TestLooper mLooper = new TestLooper();
private Context mMockContext; private MockContext mMockContext;
private Runnable mPermissionChangeCallback; private Runnable mPermissionChangeCallback;
private WrappedEntitlementManager mEnMgr; private WrappedEntitlementManager mEnMgr;
@@ -119,6 +127,13 @@ public final class EntitlementManagerTest {
public Resources getResources() { public Resources getResources() {
return mResources; return mResources;
} }
@Override
public Object getSystemService(String name) {
if (Context.ALARM_SERVICE.equals(name)) return mAlarmManager;
return super.getSystemService(name);
}
} }
public class WrappedEntitlementManager extends EntitlementManager { public class WrappedEntitlementManager extends EntitlementManager {
@@ -184,6 +199,11 @@ public final class EntitlementManagerTest {
assertEquals(config.activeDataSubId, assertEquals(config.activeDataSubId,
intent.getIntExtra(EXTRA_TETHER_SUBID, INVALID_SUBSCRIPTION_ID)); intent.getIntExtra(EXTRA_TETHER_SUBID, INVALID_SUBSCRIPTION_ID));
} }
@Override
PendingIntent createRecheckAlarmIntent() {
return mAlarmIntent;
}
} }
@Before @Before
@@ -245,6 +265,8 @@ public final class EntitlementManagerTest {
.thenReturn(PROVISIONING_NO_UI_APP_NAME); .thenReturn(PROVISIONING_NO_UI_APP_NAME);
when(mResources.getString(R.string.config_mobile_hotspot_provision_response)).thenReturn( when(mResources.getString(R.string.config_mobile_hotspot_provision_response)).thenReturn(
PROVISIONING_APP_RESPONSE); PROVISIONING_APP_RESPONSE);
when(mResources.getInteger(R.integer.config_mobile_hotspot_provision_check_period))
.thenReturn(RECHECK_TIMER_HOURS);
// Act like the CarrierConfigManager is present and ready unless told otherwise. // Act like the CarrierConfigManager is present and ready unless told otherwise.
when(mContext.getSystemService(Context.CARRIER_CONFIG_SERVICE)) when(mContext.getSystemService(Context.CARRIER_CONFIG_SERVICE))
.thenReturn(mCarrierConfigManager); .thenReturn(mCarrierConfigManager);
@@ -629,4 +651,31 @@ public final class EntitlementManagerTest {
mEnMgr.stopProvisioningIfNeeded(TETHERING_WIFI); mEnMgr.stopProvisioningIfNeeded(TETHERING_WIFI);
assertFalse(mEnMgr.isCellularUpstreamPermitted()); assertFalse(mEnMgr.isCellularUpstreamPermitted());
} }
private void sendProvisioningRecheckAlarm() {
final Intent intent = new Intent(EntitlementManager.ACTION_PROVISIONING_ALARM);
mMockContext.sendBroadcastAsUser(intent, UserHandle.ALL);
mLooper.dispatchAll();
}
@Test
public void testScheduleProvisioningReCheck() throws Exception {
setupForRequiredProvisioning();
assertFalse(mEnMgr.isCellularUpstreamPermitted());
mEnMgr.fakeEntitlementResult = TETHER_ERROR_NO_ERROR;
mEnMgr.notifyUpstream(true);
mLooper.dispatchAll();
mEnMgr.startProvisioningIfNeeded(TETHERING_WIFI, true);
mLooper.dispatchAll();
assertTrue(mEnMgr.isCellularUpstreamPermitted());
verify(mAlarmManager).setExact(eq(AlarmManager.ELAPSED_REALTIME_WAKEUP), anyLong(),
eq(mAlarmIntent));
reset(mAlarmManager);
sendProvisioningRecheckAlarm();
verify(mAlarmManager).cancel(eq(mAlarmIntent));
verify(mAlarmManager).setExact(eq(AlarmManager.ELAPSED_REALTIME_WAKEUP), anyLong(),
eq(mAlarmIntent));
}
} }