0

[AW][ComponentUpdater] Override Service#onStartCommand for testing

Override AwComponentUpdateService#onStartCommand to run the native
update service. This way it's possible to deterministically force
launch the service on devices running android M and below for
testing purposes where it's not possible to force launch the job
service via `adb shell cmd jobscheduler`.

The service isn't exported so other apps can't start the service.

The service can be launched using the commandline:
`adb shell am startservice <webview-package-name>/org.chromium.android_webview.nonembedded.AwComponentUpdateService`

Fixed: 1209275
Test: Manually launch the service via adb, run webview shell and see scheduled jobs
Change-Id: I994b46e5b250e4f42498dc20b4b89c11ea452485
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2905562
Reviewed-by: Mugdha Lakhani <nator@chromium.org>
Reviewed-by: Richard Coles <torne@chromium.org>
Commit-Queue: Hazem Ashmawy <hazems@chromium.org>
Cr-Commit-Position: refs/heads/master@{#894619}
This commit is contained in:
Hazem Ashmawy
2021-06-22 11:08:54 +00:00
committed by Chromium LUCI CQ
parent fdb9894661
commit ebccaf66ab

@ -6,6 +6,7 @@ package org.chromium.android_webview.nonembedded;
import android.app.job.JobParameters;
import android.app.job.JobService;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.os.SystemClock;
@ -48,8 +49,65 @@ public class AwComponentUpdateService extends JobService {
private static final String SHARED_PREFERENCES_NAME = "AwComponentUpdateServicePreferences";
private static final String KEY_UNEXPECTED_EXIT = "UnexpectedExit";
/**
* The service can be both started by {@link android.app.job.JobScheduler} as a {@link
* JobService} and as a started service by calling {@link Context#startService}. These two
* states can apply at the same time. The service won't stop until all necessary stop
* methods are called:
* - Calling jobFinished if it's launched as a JobService.
* - Calling stopSelf if it's launched as a start service.
*/
// If it has a non zero value, then the service is running via onStartCommand.
private int mServiceStartedId;
// If not null then the service is running as a Job service.
private JobParameters mJobParameters;
private boolean isServiceRunning() {
return mJobParameters != null || mServiceStartedId != 0;
}
// Called by JobScheduler.
@Override
public boolean onStartJob(JobParameters params) {
assert mJobParameters == null;
mJobParameters = params;
if (isServiceRunning()) {
return true;
}
return startNativeService();
}
// Called by JobScheduler.
@Override
public boolean onStopJob(JobParameters params) {
setUnexpectedExit(false);
mJobParameters = null;
// This should only be called if the service needs to be shut down before we've called
// jobFinished. Request reschedule so we can finish downloading component updates.
return /*reschedule= */ true;
}
// For testing only. To manually start the service on Android builds <= M where force running
// the job service doesn't work. The service isn't exported, so other apps won't be able to
// force start the service.
// Note: This can be simpilified when we stop supporting Android M in WebView (no need to store
// the state of how the service is running) or when manually starting the service on M isn't
// needed.
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
if (!isServiceRunning() && !startNativeService()) {
stopSelf(startId);
} else {
// Always keep the most recent startId as this is the one that should be used to stop
// the service.
mServiceStartedId = startId;
}
return START_STICKY;
}
private boolean startNativeService() {
maybeRecordUnexpectedExit();
// TODO(http://crbug.com/1179297) look at doing this in a task on a background thread
@ -62,8 +120,8 @@ public class AwComponentUpdateService extends JobService {
recordJobDuration(SystemClock.uptimeMillis() - startTime);
recordFilesChanged(count);
recordDirectorySize();
jobFinished(params, /* needReschedule= */ false);
setUnexpectedExit(false);
stopService();
});
return true;
}
@ -71,13 +129,18 @@ public class AwComponentUpdateService extends JobService {
return false;
}
@Override
public boolean onStopJob(JobParameters params) {
setUnexpectedExit(false);
// This should only be called if the service needs to be shut down before we've called
// jobFinished. Request reschedule so we can finish downloading component updates.
return /*reschedule= */ true;
// Call the appropriate stop method according to how the service is launched.
private void stopService() {
// Service is launched as a started service.
if (mServiceStartedId > 0) {
stopSelf(mServiceStartedId);
mServiceStartedId = 0;
}
// Service is launched as a job service.
if (mJobParameters != null) {
jobFinished(mJobParameters, /* needReschedule= */ false);
mJobParameters = null;
}
}
private void recordDirectorySize() {