Merge "Add BinaryTransparencyService as new SystemService."
This commit is contained in:
@@ -28,6 +28,11 @@ filegroup {
|
||||
srcs: ["com/android/internal/os/IDropBoxManagerService.aidl"],
|
||||
}
|
||||
|
||||
filegroup {
|
||||
name: "IBinaryTransparencyService.aidl",
|
||||
srcs: ["com/android/internal/os/IBinaryTransparencyService.aidl"],
|
||||
}
|
||||
|
||||
filegroup {
|
||||
name: "ITracingServiceProxy.aidl",
|
||||
srcs: ["android/tracing/ITracingServiceProxy.aidl"],
|
||||
|
||||
@@ -215,6 +215,7 @@ import android.telecom.TelecomManager;
|
||||
import android.telephony.MmsManager;
|
||||
import android.telephony.TelephonyFrameworkInitializer;
|
||||
import android.telephony.TelephonyRegistryManager;
|
||||
import android.transparency.BinaryTransparencyManager;
|
||||
import android.util.ArrayMap;
|
||||
import android.util.Log;
|
||||
import android.util.Slog;
|
||||
@@ -245,6 +246,7 @@ import com.android.internal.app.ISoundTriggerService;
|
||||
import com.android.internal.appwidget.IAppWidgetService;
|
||||
import com.android.internal.graphics.fonts.IFontManager;
|
||||
import com.android.internal.net.INetworkWatchlistManager;
|
||||
import com.android.internal.os.IBinaryTransparencyService;
|
||||
import com.android.internal.os.IDropBoxManagerService;
|
||||
import com.android.internal.policy.PhoneLayoutInflater;
|
||||
import com.android.internal.util.Preconditions;
|
||||
@@ -496,6 +498,17 @@ public final class SystemServiceRegistry {
|
||||
return new DropBoxManager(ctx, service);
|
||||
}});
|
||||
|
||||
registerService(Context.BINARY_TRANSPARENCY_SERVICE, BinaryTransparencyManager.class,
|
||||
new CachedServiceFetcher<BinaryTransparencyManager>() {
|
||||
@Override
|
||||
public BinaryTransparencyManager createService(ContextImpl ctx)
|
||||
throws ServiceNotFoundException {
|
||||
IBinder b = ServiceManager.getServiceOrThrow(
|
||||
Context.BINARY_TRANSPARENCY_SERVICE);
|
||||
IBinaryTransparencyService service = IBinaryTransparencyService.Stub.asInterface(b);
|
||||
return new BinaryTransparencyManager(ctx, service);
|
||||
}});
|
||||
|
||||
registerService(Context.INPUT_SERVICE, InputManager.class,
|
||||
new StaticServiceFetcher<InputManager>() {
|
||||
@Override
|
||||
|
||||
@@ -5106,6 +5106,16 @@ public abstract class Context {
|
||||
*/
|
||||
public static final String DROPBOX_SERVICE = "dropbox";
|
||||
|
||||
/**
|
||||
* System service name for BinaryTransparencyService. This is used to retrieve measurements
|
||||
* pertaining to various pre-installed and system binaries on device for the purposes of
|
||||
* providing transparency to the user.
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
@SuppressLint("ServiceName")
|
||||
public static final String BINARY_TRANSPARENCY_SERVICE = "transparency";
|
||||
|
||||
/**
|
||||
* System service name for the DeviceIdleManager.
|
||||
* @see #getSystemService(String)
|
||||
|
||||
@@ -0,0 +1,83 @@
|
||||
/*
|
||||
* 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.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package android.transparency;
|
||||
|
||||
import android.annotation.NonNull;
|
||||
import android.annotation.SystemService;
|
||||
import android.content.Context;
|
||||
import android.os.RemoteException;
|
||||
import android.util.Slog;
|
||||
|
||||
import com.android.internal.os.IBinaryTransparencyService;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* BinaryTransparencyManager defines a number of system interfaces that other system apps or
|
||||
* services can make use of, when trying to get more information about the various binaries
|
||||
* that are installed on this device.
|
||||
* @hide
|
||||
*/
|
||||
@SystemService(Context.BINARY_TRANSPARENCY_SERVICE)
|
||||
public class BinaryTransparencyManager {
|
||||
private static final String TAG = "TransparencyManager";
|
||||
|
||||
private final Context mContext;
|
||||
private final IBinaryTransparencyService mService;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
* @param context The calling context.
|
||||
* @param service A valid instance of IBinaryTransparencyService.
|
||||
* @hide
|
||||
*/
|
||||
public BinaryTransparencyManager(Context context, IBinaryTransparencyService service) {
|
||||
mContext = context;
|
||||
mService = service;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Obtains a string containing information that describes the signed images that are installed
|
||||
* on this device. Currently, this piece of information is identified as the VBMeta digest.
|
||||
* @return A String containing the VBMeta Digest of the signed partitions loaded on this device.
|
||||
*/
|
||||
@NonNull
|
||||
public String getSignedImageInfo() {
|
||||
try {
|
||||
return mService.getSignedImageInfo();
|
||||
} catch (RemoteException e) {
|
||||
throw e.rethrowFromSystemServer();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a map of all installed APEXs consisting of package name to SHA256 hash of the
|
||||
* package.
|
||||
* @return A Map with the following entries: {apex package name : sha256 digest of package}
|
||||
*/
|
||||
@NonNull
|
||||
public Map getApexInfo() {
|
||||
try {
|
||||
Slog.d(TAG, "Calling backend's getApexInfo()");
|
||||
return mService.getApexInfo();
|
||||
} catch (RemoteException e) {
|
||||
throw e.rethrowFromSystemServer();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
4
core/java/android/transparency/OWNERS
Normal file
4
core/java/android/transparency/OWNERS
Normal file
@@ -0,0 +1,4 @@
|
||||
# Bug component: 36824
|
||||
billylau@google.com
|
||||
vishwath@google.com
|
||||
mpgroover@google.com
|
||||
@@ -0,0 +1,30 @@
|
||||
/*
|
||||
* 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.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.internal.os;
|
||||
|
||||
/**
|
||||
* "Backend" interface used by {@link android.os.BinaryTransparencyManager} to talk to the
|
||||
* BinaryTransparencyService that actually implements the measurement and information aggregation
|
||||
* functionality.
|
||||
*
|
||||
* @see BinaryTransparencyManager
|
||||
*/
|
||||
interface IBinaryTransparencyService {
|
||||
String getSignedImageInfo();
|
||||
|
||||
Map getApexInfo();
|
||||
}
|
||||
@@ -2,6 +2,7 @@ per-file *Power* = file:/services/core/java/com/android/server/power/OWNERS
|
||||
per-file *Zygote* = file:/ZYGOTE_OWNERS
|
||||
per-file *Cpu* = file:CPU_OWNERS
|
||||
per-file *Binder* = file:BINDER_OWNERS
|
||||
per-file *BinaryTransparency* = file:/core/java/android/transparency/OWNERS
|
||||
|
||||
# BatteryStats
|
||||
per-file BatterySipper.java = file:/BATTERY_STATS_OWNERS
|
||||
|
||||
@@ -0,0 +1,525 @@
|
||||
/*
|
||||
* 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.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.server;
|
||||
|
||||
import android.annotation.NonNull;
|
||||
import android.annotation.Nullable;
|
||||
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.RemoteException;
|
||||
import android.os.ResultReceiver;
|
||||
import android.os.ShellCallback;
|
||||
import android.os.ShellCommand;
|
||||
import android.os.SystemProperties;
|
||||
import android.util.PackageUtils;
|
||||
import android.util.Slog;
|
||||
|
||||
import com.android.internal.os.IBinaryTransparencyService;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileDescriptor;
|
||||
import java.io.IOException;
|
||||
import java.io.PrintWriter;
|
||||
import java.nio.file.Files;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* @hide
|
||||
*/
|
||||
public class BinaryTransparencyService extends SystemService {
|
||||
private static final String TAG = "TransparencyService";
|
||||
|
||||
private static final String VBMETA_DIGEST_UNINITIALIZED = "vbmeta-digest-uninitialized";
|
||||
private static final String VBMETA_DIGEST_UNAVAILABLE = "vbmeta-digest-unavailable";
|
||||
private static final String SYSPROP_NAME_VBETA_DIGEST = "ro.boot.vbmeta.digest";
|
||||
|
||||
private static final String BINARY_HASH_ERROR = "SHA256HashError";
|
||||
|
||||
private final Context mContext;
|
||||
private String mVbmetaDigest;
|
||||
private HashMap<String, String> mBinaryHashes;
|
||||
private HashMap<String, Long> mBinaryLastUpdateTimes;
|
||||
|
||||
final class BinaryTransparencyServiceImpl extends IBinaryTransparencyService.Stub {
|
||||
|
||||
@Override
|
||||
public String getSignedImageInfo() {
|
||||
return mVbmetaDigest;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map getApexInfo() {
|
||||
HashMap results = new HashMap();
|
||||
if (!updateBinaryMeasurements()) {
|
||||
Slog.e(TAG, "Error refreshing APEX measurements.");
|
||||
return results;
|
||||
}
|
||||
PackageManager pm = mContext.getPackageManager();
|
||||
if (pm == null) {
|
||||
Slog.e(TAG, "Error obtaining an instance of PackageManager.");
|
||||
return results;
|
||||
}
|
||||
|
||||
for (PackageInfo packageInfo : getInstalledApexs()) {
|
||||
results.put(packageInfo, mBinaryHashes.get(packageInfo.packageName));
|
||||
}
|
||||
|
||||
return results;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onShellCommand(@Nullable FileDescriptor in,
|
||||
@Nullable FileDescriptor out,
|
||||
@Nullable FileDescriptor err,
|
||||
@NonNull String[] args,
|
||||
@Nullable ShellCallback callback,
|
||||
@NonNull ResultReceiver resultReceiver) throws RemoteException {
|
||||
(new ShellCommand() {
|
||||
|
||||
private int printSignedImageInfo() {
|
||||
final PrintWriter pw = getOutPrintWriter();
|
||||
boolean listAllPartitions = false;
|
||||
String opt;
|
||||
|
||||
while ((opt = getNextOption()) != null) {
|
||||
switch (opt) {
|
||||
case "-a":
|
||||
listAllPartitions = true;
|
||||
break;
|
||||
default:
|
||||
pw.println("ERROR: Unknown option: " + opt);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
final String signedImageInfo = getSignedImageInfo();
|
||||
pw.println("Image Info:");
|
||||
pw.println(Build.FINGERPRINT);
|
||||
pw.println(signedImageInfo);
|
||||
pw.println("");
|
||||
|
||||
if (listAllPartitions) {
|
||||
PackageManager pm = mContext.getPackageManager();
|
||||
if (pm == null) {
|
||||
pw.println("ERROR: Failed to obtain an instance of package manager.");
|
||||
return -1;
|
||||
}
|
||||
|
||||
pw.println("Other partitions:");
|
||||
List<Build.Partition> buildPartitions = Build.getFingerprintedPartitions();
|
||||
for (Build.Partition buildPartition : buildPartitions) {
|
||||
pw.println("Name: " + buildPartition.getName());
|
||||
pw.println("Fingerprint: " + buildPartition.getFingerprint());
|
||||
pw.println("Build time (ms): " + buildPartition.getBuildTimeMillis());
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
private void printModuleDetails(ModuleInfo moduleInfo, final PrintWriter pw) {
|
||||
pw.println("--- Module Details ---");
|
||||
pw.println("Module name: " + moduleInfo.getName());
|
||||
pw.println("Module visibility: "
|
||||
+ (moduleInfo.isHidden() ? "hidden" : "visible"));
|
||||
}
|
||||
|
||||
private int printAllApexs() {
|
||||
final PrintWriter pw = getOutPrintWriter();
|
||||
boolean verbose = false;
|
||||
String opt;
|
||||
|
||||
// refresh cache to make sure info is most up-to-date
|
||||
if (!updateBinaryMeasurements()) {
|
||||
pw.println("ERROR: Failed to refresh info for APEXs.");
|
||||
return -1;
|
||||
}
|
||||
if (mBinaryHashes == null || (mBinaryHashes.size() == 0)) {
|
||||
pw.println("ERROR: Unable to obtain apex_info at this time.");
|
||||
return -1;
|
||||
}
|
||||
|
||||
while ((opt = getNextOption()) != null) {
|
||||
switch (opt) {
|
||||
case "-v":
|
||||
verbose = true;
|
||||
break;
|
||||
default:
|
||||
pw.println("ERROR: Unknown option: " + opt);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
PackageManager pm = mContext.getPackageManager();
|
||||
if (pm == null) {
|
||||
pw.println("ERROR: Failed to obtain an instance of package manager.");
|
||||
return -1;
|
||||
}
|
||||
|
||||
pw.println("APEX Info:");
|
||||
for (PackageInfo packageInfo : getInstalledApexs()) {
|
||||
String packageName = packageInfo.packageName;
|
||||
pw.println(packageName + ";"
|
||||
+ packageInfo.getLongVersionCode() + ":"
|
||||
+ mBinaryHashes.get(packageName).toLowerCase());
|
||||
|
||||
if (verbose) {
|
||||
pw.println("Install location: "
|
||||
+ packageInfo.applicationInfo.sourceDir);
|
||||
pw.println("Last Update Time (ms): " + packageInfo.lastUpdateTime);
|
||||
|
||||
ModuleInfo moduleInfo;
|
||||
try {
|
||||
moduleInfo = pm.getModuleInfo(packageInfo.packageName, 0);
|
||||
} catch (PackageManager.NameNotFoundException e) {
|
||||
pw.println("Is A Module: False");
|
||||
pw.println("");
|
||||
continue;
|
||||
}
|
||||
pw.println("Is A Module: True");
|
||||
printModuleDetails(moduleInfo, pw);
|
||||
pw.println("");
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
private int printAllModules() {
|
||||
final PrintWriter pw = getOutPrintWriter();
|
||||
boolean verbose = false;
|
||||
String opt;
|
||||
|
||||
// refresh cache to make sure info is most up-to-date
|
||||
if (!updateBinaryMeasurements()) {
|
||||
pw.println("ERROR: Failed to refresh info for Modules.");
|
||||
return -1;
|
||||
}
|
||||
if (mBinaryHashes == null || (mBinaryHashes.size() == 0)) {
|
||||
pw.println("ERROR: Unable to obtain module_info at this time.");
|
||||
return -1;
|
||||
}
|
||||
|
||||
while ((opt = getNextOption()) != null) {
|
||||
switch (opt) {
|
||||
case "-v":
|
||||
verbose = true;
|
||||
break;
|
||||
default:
|
||||
pw.println("ERROR: Unknown option: " + opt);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
PackageManager pm = mContext.getPackageManager();
|
||||
if (pm == null) {
|
||||
pw.println("ERROR: Failed to obtain an instance of package manager.");
|
||||
return -1;
|
||||
}
|
||||
|
||||
pw.println("Module Info:");
|
||||
for (ModuleInfo module : pm.getInstalledModules(PackageManager.MATCH_ALL)) {
|
||||
String packageName = module.getPackageName();
|
||||
try {
|
||||
PackageInfo packageInfo = pm.getPackageInfo(packageName,
|
||||
PackageManager.MATCH_APEX);
|
||||
pw.println(packageInfo.packageName + ";"
|
||||
+ packageInfo.getLongVersionCode() + ":"
|
||||
+ mBinaryHashes.get(packageName).toLowerCase());
|
||||
|
||||
if (verbose) {
|
||||
pw.println("Install location: "
|
||||
+ packageInfo.applicationInfo.sourceDir);
|
||||
printModuleDetails(module, pw);
|
||||
pw.println("");
|
||||
}
|
||||
} catch (PackageManager.NameNotFoundException e) {
|
||||
pw.println(packageName);
|
||||
pw.println(packageName
|
||||
+ ";ERROR:Unable to find PackageInfo for this module.");
|
||||
if (verbose) {
|
||||
printModuleDetails(module, pw);
|
||||
pw.println("");
|
||||
}
|
||||
continue;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int onCommand(String cmd) {
|
||||
if (cmd == null) {
|
||||
return handleDefaultCommands(cmd);
|
||||
}
|
||||
|
||||
final PrintWriter pw = getOutPrintWriter();
|
||||
switch (cmd) {
|
||||
case "get": {
|
||||
final String infoType = getNextArg();
|
||||
if (infoType == null) {
|
||||
printHelpMenu();
|
||||
return -1;
|
||||
}
|
||||
|
||||
switch (infoType) {
|
||||
case "image_info":
|
||||
return printSignedImageInfo();
|
||||
case "apex_info":
|
||||
return printAllApexs();
|
||||
case "module_info":
|
||||
return printAllModules();
|
||||
default:
|
||||
pw.println(String.format("ERROR: Unknown info type '%s'",
|
||||
infoType));
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
default:
|
||||
return handleDefaultCommands(cmd);
|
||||
}
|
||||
}
|
||||
|
||||
private void printHelpMenu() {
|
||||
final PrintWriter pw = getOutPrintWriter();
|
||||
pw.println("Transparency manager (transparency) commands:");
|
||||
pw.println(" help");
|
||||
pw.println(" Print this help text.");
|
||||
pw.println("");
|
||||
pw.println(" get image_info [-a]");
|
||||
pw.println(" Print information about loaded image (firmware). Options:");
|
||||
pw.println(" -a: lists all other identifiable partitions.");
|
||||
pw.println("");
|
||||
pw.println(" get apex_info [-v]");
|
||||
pw.println(" Print information about installed APEXs on device.");
|
||||
pw.println(" -v: lists more verbose information about each APEX");
|
||||
pw.println("");
|
||||
pw.println(" get module_info [-v]");
|
||||
pw.println(" Print information about installed modules on device.");
|
||||
pw.println(" -v: lists more verbose information about each module");
|
||||
pw.println("");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onHelp() {
|
||||
printHelpMenu();
|
||||
}
|
||||
}).exec(this, in, out, err, args, callback, resultReceiver);
|
||||
}
|
||||
}
|
||||
private final BinaryTransparencyServiceImpl mServiceImpl;
|
||||
|
||||
public BinaryTransparencyService(Context context) {
|
||||
super(context);
|
||||
mContext = context;
|
||||
mServiceImpl = new BinaryTransparencyServiceImpl();
|
||||
mVbmetaDigest = VBMETA_DIGEST_UNINITIALIZED;
|
||||
mBinaryHashes = new HashMap<>();
|
||||
mBinaryLastUpdateTimes = new HashMap<>();
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when the system service should publish a binder service using
|
||||
* {@link #publishBinderService(String, IBinder).}
|
||||
*/
|
||||
@Override
|
||||
public void onStart() {
|
||||
try {
|
||||
publishBinderService(Context.BINARY_TRANSPARENCY_SERVICE, mServiceImpl);
|
||||
Slog.i(TAG, "Started BinaryTransparencyService");
|
||||
} catch (Throwable t) {
|
||||
Slog.e(TAG, "Failed to start BinaryTransparencyService.", t);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Called on each phase of the boot process. Phases before the service's start phase
|
||||
* (as defined in the @Service annotation) are never received.
|
||||
*
|
||||
* @param phase The current boot phase.
|
||||
*/
|
||||
@Override
|
||||
public void onBootPhase(int phase) {
|
||||
|
||||
// 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();
|
||||
}
|
||||
}
|
||||
|
||||
private void getVBMetaDigestInformation() {
|
||||
mVbmetaDigest = SystemProperties.get(SYSPROP_NAME_VBETA_DIGEST, VBMETA_DIGEST_UNAVAILABLE);
|
||||
Slog.d(TAG, String.format("VBMeta Digest: %s", mVbmetaDigest));
|
||||
}
|
||||
|
||||
@NonNull
|
||||
private List<PackageInfo> getInstalledApexs() {
|
||||
List<PackageInfo> results = new ArrayList<PackageInfo>();
|
||||
PackageManager pm = mContext.getPackageManager();
|
||||
if (pm == null) {
|
||||
Slog.e(TAG, "Error obtaining an instance of PackageManager.");
|
||||
return results;
|
||||
}
|
||||
List<PackageInfo> allPackages = pm.getInstalledPackages(
|
||||
PackageManager.PackageInfoFlags.of(PackageManager.MATCH_APEX));
|
||||
if (allPackages == null) {
|
||||
Slog.e(TAG, "Error obtaining installed packages (including APEX)");
|
||||
return results;
|
||||
}
|
||||
|
||||
results = allPackages.stream().filter(p -> p.isApex).collect(Collectors.toList());
|
||||
return results;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Updates the internal data structure with the most current APEX measurements.
|
||||
* @return true if update is successful; false otherwise.
|
||||
*/
|
||||
private boolean updateBinaryMeasurements() {
|
||||
if (mBinaryHashes.size() == 0) {
|
||||
Slog.d(TAG, "No apex in cache yet.");
|
||||
doFreshBinaryMeasurements();
|
||||
return true;
|
||||
}
|
||||
|
||||
PackageManager pm = mContext.getPackageManager();
|
||||
if (pm == null) {
|
||||
Slog.e(TAG, "Failed to obtain a valid PackageManager instance.");
|
||||
return false;
|
||||
}
|
||||
|
||||
// We're assuming updates to existing modules and APEXs can happen, but not brand new
|
||||
// ones appearing out of the blue. Thus, we're going to only go through our cache to check
|
||||
// for changes, rather than freshly invoking `getInstalledPackages()` and
|
||||
// `getInstalledModules()`
|
||||
for (Map.Entry<String, Long> entry : mBinaryLastUpdateTimes.entrySet()) {
|
||||
String packageName = entry.getKey();
|
||||
try {
|
||||
PackageInfo packageInfo = pm.getPackageInfo(packageName,
|
||||
PackageManager.PackageInfoFlags.of(PackageManager.MATCH_APEX));
|
||||
long cachedUpdateTime = entry.getValue();
|
||||
|
||||
if (packageInfo.lastUpdateTime > cachedUpdateTime) {
|
||||
Slog.d(TAG, packageName + " has been updated!");
|
||||
entry.setValue(packageInfo.lastUpdateTime);
|
||||
|
||||
// compute the digest for the updated package
|
||||
String sha256digest = computeSha256DigestOfFile(
|
||||
packageInfo.applicationInfo.sourceDir);
|
||||
if (sha256digest == null) {
|
||||
Slog.e(TAG, "Failed to compute SHA256sum for file at "
|
||||
+ packageInfo.applicationInfo.sourceDir);
|
||||
mBinaryHashes.put(packageName, BINARY_HASH_ERROR);
|
||||
} else {
|
||||
mBinaryHashes.put(packageName, sha256digest);
|
||||
}
|
||||
}
|
||||
} catch (PackageManager.NameNotFoundException e) {
|
||||
Slog.e(TAG, "Could not find package with name " + packageName);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private void doFreshBinaryMeasurements() {
|
||||
PackageManager pm = mContext.getPackageManager();
|
||||
Slog.d(TAG, "Obtained package manager");
|
||||
|
||||
// In general, we care about all APEXs, *and* all Modules, which may include some APKs.
|
||||
|
||||
// First, we deal with all installed APEXs.
|
||||
for (PackageInfo packageInfo : getInstalledApexs()) {
|
||||
ApplicationInfo appInfo = packageInfo.applicationInfo;
|
||||
|
||||
// compute SHA256 for these APEXs
|
||||
String sha256digest = computeSha256DigestOfFile(appInfo.sourceDir);
|
||||
if (sha256digest == null) {
|
||||
Slog.e(TAG, String.format("Failed to compute SHA256 digest for %s",
|
||||
packageInfo.packageName));
|
||||
mBinaryHashes.put(packageInfo.packageName, BINARY_HASH_ERROR);
|
||||
} else {
|
||||
mBinaryHashes.put(packageInfo.packageName, sha256digest);
|
||||
}
|
||||
Slog.d(TAG, String.format("Last update time for %s: %d", packageInfo.packageName,
|
||||
packageInfo.lastUpdateTime));
|
||||
mBinaryLastUpdateTimes.put(packageInfo.packageName, packageInfo.lastUpdateTime);
|
||||
}
|
||||
|
||||
// Next, get all installed modules from PackageManager - skip over those APEXs we've
|
||||
// processed above
|
||||
for (ModuleInfo module : pm.getInstalledModules(PackageManager.MATCH_ALL)) {
|
||||
String packageName = module.getPackageName();
|
||||
if (packageName == null) {
|
||||
Slog.e(TAG, "ERROR: Encountered null package name for module "
|
||||
+ module.getApexModuleName());
|
||||
continue;
|
||||
}
|
||||
if (mBinaryHashes.containsKey(module.getPackageName())) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// get PackageInfo for this module
|
||||
try {
|
||||
PackageInfo packageInfo = pm.getPackageInfo(packageName,
|
||||
PackageManager.PackageInfoFlags.of(PackageManager.MATCH_APEX));
|
||||
ApplicationInfo appInfo = packageInfo.applicationInfo;
|
||||
|
||||
// compute SHA256 digest for these modules
|
||||
String sha256digest = computeSha256DigestOfFile(appInfo.sourceDir);
|
||||
if (sha256digest == null) {
|
||||
Slog.e(TAG, String.format("Failed to compute SHA256 digest for %s",
|
||||
packageName));
|
||||
mBinaryHashes.put(packageName, BINARY_HASH_ERROR);
|
||||
} else {
|
||||
mBinaryHashes.put(packageName, sha256digest);
|
||||
}
|
||||
Slog.d(TAG, String.format("Last update time for %s: %d", packageName,
|
||||
packageInfo.lastUpdateTime));
|
||||
mBinaryLastUpdateTimes.put(packageName, packageInfo.lastUpdateTime);
|
||||
} catch (PackageManager.NameNotFoundException e) {
|
||||
Slog.e(TAG, "ERROR: Could not obtain PackageInfo for package name: "
|
||||
+ packageName);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private String computeSha256DigestOfFile(@NonNull String pathToFile) {
|
||||
File apexFile = new File(pathToFile);
|
||||
|
||||
try {
|
||||
byte[] apexFileBytes = Files.readAllBytes(apexFile.toPath());
|
||||
return PackageUtils.computeSha256Digest(apexFileBytes);
|
||||
} catch (IOException e) {
|
||||
Slog.e(TAG, String.format("I/O error occurs when reading from %s", pathToFile));
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -22,6 +22,7 @@ per-file BatteryService.java = file:platform/hardware/interfaces:/health/aidl/OW
|
||||
per-file *Alarm* = file:/apex/jobscheduler/OWNERS
|
||||
per-file *AppOp* = file:/core/java/android/permission/OWNERS
|
||||
per-file *Battery* = file:/BATTERY_STATS_OWNERS
|
||||
per-file *BinaryTransparency* = file:/core/java/android/transparency/OWNERS
|
||||
per-file *Binder* = file:/core/java/com/android/internal/os/BINDER_OWNERS
|
||||
per-file *Bluetooth* = file:/core/java/android/bluetooth/OWNERS
|
||||
per-file *Gnss* = file:/services/core/java/com/android/server/location/OWNERS
|
||||
|
||||
@@ -1454,6 +1454,10 @@ public final class SystemServer implements Dumpable {
|
||||
mSystemServiceManager.startService(KeyChainSystemService.class);
|
||||
t.traceEnd();
|
||||
|
||||
t.traceBegin("StartBinaryTransparencyService");
|
||||
mSystemServiceManager.startService(BinaryTransparencyService.class);
|
||||
t.traceEnd();
|
||||
|
||||
t.traceBegin("StartSchedulingPolicyService");
|
||||
ServiceManager.addService("scheduling_policy", new SchedulingPolicyService());
|
||||
t.traceEnd();
|
||||
|
||||
Reference in New Issue
Block a user