Schedule binary measurement job at boot completed.
Instead of waiting until first invocation of commandline, we are scheduling the computation of SHA256 digest of APEXs and Modules at post boot such that the job can be run when the device is idle. For this purpose, an inner static class that extends JobServer is created, and a declaration of this service in the manifest which is protected by BIND_JOB_SERVICE is also necessary. This allows the logging of APEX information to statsd to still happen at least once every reboot (when the device is idle). Otherwise, logging may never occur if the users never make use of the commandline. Bug: 217469982 Test: Manual. Job is found to be triggered automatically when device is left overnight. Job can also be manually triggered (for test) via `adb shell cmd jobscheduler run android <job_id>` Job id can be found via printout in logcat after the scheduling is successfully done. After job is run, `adb shell cmd transparency get apex_info` no longer has latency upon first invocation. Change-Id: I7cff80d53b37152639bb9aebaca50f5b61733ea7
This commit is contained in:
@@ -6916,6 +6916,10 @@
|
||||
android:permission="android.permission.BIND_JOB_SERVICE">
|
||||
</service>
|
||||
|
||||
<service android:name="com.android.server.BinaryTransparencyService$UpdateMeasurementsJobService"
|
||||
android:permission="android.permission.BIND_JOB_SERVICE">
|
||||
</service>
|
||||
|
||||
<service android:name="com.android.server.pm.PackageManagerShellCommandDataLoader"
|
||||
android:exported="false">
|
||||
<intent-filter>
|
||||
|
||||
@@ -18,14 +18,22 @@ package com.android.server;
|
||||
|
||||
import android.annotation.NonNull;
|
||||
import android.annotation.Nullable;
|
||||
import android.annotation.SuppressLint;
|
||||
import android.app.job.JobInfo;
|
||||
import android.app.job.JobParameters;
|
||||
import android.app.job.JobScheduler;
|
||||
import android.app.job.JobService;
|
||||
import android.content.ComponentName;
|
||||
import android.content.Context;
|
||||
import android.content.pm.ApplicationInfo;
|
||||
import android.content.pm.ModuleInfo;
|
||||
import android.content.pm.PackageInfo;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.os.Build;
|
||||
import android.os.IBinder;
|
||||
import android.os.RemoteException;
|
||||
import android.os.ResultReceiver;
|
||||
import android.os.ServiceManager;
|
||||
import android.os.ShellCallback;
|
||||
import android.os.ShellCommand;
|
||||
import android.os.SystemProperties;
|
||||
@@ -42,6 +50,7 @@ import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
@@ -49,6 +58,7 @@ import java.util.stream.Collectors;
|
||||
*/
|
||||
public class BinaryTransparencyService extends SystemService {
|
||||
private static final String TAG = "TransparencyService";
|
||||
private static final String EXTRA_SERVICE = "service";
|
||||
|
||||
@VisibleForTesting
|
||||
static final String VBMETA_DIGEST_UNINITIALIZED = "vbmeta-digest-uninitialized";
|
||||
@@ -365,10 +375,80 @@ public class BinaryTransparencyService extends SystemService {
|
||||
|
||||
// we are only interested in doing things at PHASE_BOOT_COMPLETED
|
||||
if (phase == PHASE_BOOT_COMPLETED) {
|
||||
// due to potentially long computation that holds up boot time, apex sha computations
|
||||
// are deferred to first call
|
||||
Slog.i(TAG, "Boot completed. Getting VBMeta Digest.");
|
||||
getVBMetaDigestInformation();
|
||||
|
||||
// due to potentially long computation that holds up boot time, computations for
|
||||
// SHA256 digests of APEX and Module packages are scheduled here,
|
||||
// but only executed when device is idle.
|
||||
Slog.i(TAG, "Scheduling APEX and Module measurements to be updated.");
|
||||
UpdateMeasurementsJobService.scheduleBinaryMeasurements(mContext,
|
||||
BinaryTransparencyService.this);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* JobService to update binary measurements and update internal cache.
|
||||
*/
|
||||
public static class UpdateMeasurementsJobService extends JobService {
|
||||
private static final int COMPUTE_APEX_MODULE_SHA256_JOB_ID =
|
||||
BinaryTransparencyService.UpdateMeasurementsJobService.class.hashCode();
|
||||
|
||||
@Override
|
||||
public boolean onStartJob(JobParameters params) {
|
||||
Slog.d(TAG, "Job to update binary measurements started.");
|
||||
if (params.getJobId() != COMPUTE_APEX_MODULE_SHA256_JOB_ID) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// we'll still update the measurements via threads to be mindful of low-end devices
|
||||
// where this operation might take longer than expected, and so that we don't block
|
||||
// system_server's main thread.
|
||||
Executors.defaultThreadFactory().newThread(() -> {
|
||||
// since we can't call updateBinaryMeasurements() directly, calling
|
||||
// getApexInfo() achieves the same effect, and we simply discard the return
|
||||
// value
|
||||
|
||||
IBinder b = ServiceManager.getService(Context.BINARY_TRANSPARENCY_SERVICE);
|
||||
IBinaryTransparencyService iBtsService =
|
||||
IBinaryTransparencyService.Stub.asInterface(b);
|
||||
try {
|
||||
iBtsService.getApexInfo();
|
||||
} catch (RemoteException e) {
|
||||
Slog.e(TAG, "Updating binary measurements was interrupted.", e);
|
||||
return;
|
||||
}
|
||||
jobFinished(params, false);
|
||||
}).start();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onStopJob(JobParameters params) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@SuppressLint("DefaultLocale")
|
||||
static void scheduleBinaryMeasurements(Context context, BinaryTransparencyService service) {
|
||||
Slog.i(TAG, "Scheduling APEX & Module SHA256 digest computation job");
|
||||
final JobScheduler jobScheduler = context.getSystemService(JobScheduler.class);
|
||||
if (jobScheduler == null) {
|
||||
Slog.e(TAG, "Failed to obtain an instance of JobScheduler.");
|
||||
return;
|
||||
}
|
||||
|
||||
final JobInfo jobInfo = new JobInfo.Builder(COMPUTE_APEX_MODULE_SHA256_JOB_ID,
|
||||
new ComponentName(context, UpdateMeasurementsJobService.class))
|
||||
.setRequiresDeviceIdle(true)
|
||||
.build();
|
||||
if (jobScheduler.schedule(jobInfo) != JobScheduler.RESULT_SUCCESS) {
|
||||
Slog.e(TAG, "Failed to schedule job to update binary measurements.");
|
||||
return;
|
||||
}
|
||||
Slog.d(TAG, String.format(
|
||||
"Job %d to update binary measurements scheduled successfully.",
|
||||
COMPUTE_APEX_MODULE_SHA256_JOB_ID));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -380,7 +460,7 @@ public class BinaryTransparencyService extends SystemService {
|
||||
|
||||
@NonNull
|
||||
private List<PackageInfo> getInstalledApexs() {
|
||||
List<PackageInfo> results = new ArrayList<PackageInfo>();
|
||||
List<PackageInfo> results = new ArrayList<>();
|
||||
PackageManager pm = mContext.getPackageManager();
|
||||
if (pm == null) {
|
||||
Slog.e(TAG, "Error obtaining an instance of PackageManager.");
|
||||
|
||||
Reference in New Issue
Block a user