Fix for security logging of missing packages.
Better error cases handling. Using internal handler to process digests to not overcommit PackageManager's. Fixes: 170777013 Test: atest OrgOwnedProfileOwnerTest#testSecurityLogging Change-Id: I741c10ef3ceeec01e5436f92caa6a52d0c6b6003
This commit is contained in:
@@ -1126,4 +1126,16 @@ public abstract class PackageManagerInternal {
|
||||
* Notifies that a package has crashed or ANR'd.
|
||||
*/
|
||||
public abstract void notifyPackageCrashOrAnr(String packageName);
|
||||
|
||||
/**
|
||||
* Requesting the checksums for APKs within a package.
|
||||
* See {@link PackageManager#requestChecksums} for details.
|
||||
*
|
||||
* @param executor to use for digest calculations.
|
||||
* @param handler to use for postponed calculations.
|
||||
*/
|
||||
public abstract void requestChecksums(@NonNull String packageName, boolean includeSplits,
|
||||
@Checksum.Type int optional, @Checksum.Type int required,
|
||||
@Nullable List trustedInstallers, @NonNull IntentSender statusReceiver, int userId,
|
||||
@NonNull Executor executor, @NonNull Handler handler);
|
||||
}
|
||||
|
||||
@@ -2535,8 +2535,20 @@ public class PackageManagerService extends IPackageManager.Stub
|
||||
@Checksum.Type int optional,
|
||||
@Checksum.Type int required, @Nullable List trustedInstallers,
|
||||
@NonNull IntentSender statusReceiver, int userId) {
|
||||
requestChecksumsInternal(packageName, includeSplits, optional, required, trustedInstallers,
|
||||
statusReceiver, userId, mInjector.getBackgroundExecutor(),
|
||||
mInjector.getBackgroundHandler());
|
||||
}
|
||||
|
||||
private void requestChecksumsInternal(@NonNull String packageName, boolean includeSplits,
|
||||
@Checksum.Type int optional,
|
||||
@Checksum.Type int required, @Nullable List trustedInstallers,
|
||||
@NonNull IntentSender statusReceiver, int userId, @NonNull Executor executor,
|
||||
@NonNull Handler handler) {
|
||||
Objects.requireNonNull(packageName);
|
||||
Objects.requireNonNull(statusReceiver);
|
||||
Objects.requireNonNull(executor);
|
||||
Objects.requireNonNull(handler);
|
||||
|
||||
final ApplicationInfo applicationInfo = getApplicationInfoInternal(packageName, 0,
|
||||
Binder.getCallingUid(), userId);
|
||||
@@ -2560,10 +2572,10 @@ public class PackageManagerService extends IPackageManager.Stub
|
||||
final Certificate[] trustedCerts = (trustedInstallers != null) ? decodeCertificates(
|
||||
trustedInstallers) : null;
|
||||
|
||||
mInjector.getBackgroundExecutor().execute(() -> {
|
||||
executor.execute(() -> {
|
||||
ApkChecksums.Injector injector = new ApkChecksums.Injector(
|
||||
() -> mContext,
|
||||
() -> mInjector.getBackgroundHandler(),
|
||||
() -> handler,
|
||||
() -> mInjector.getIncrementalManager());
|
||||
ApkChecksums.getChecksums(filesToChecksum, optional, required, trustedCerts,
|
||||
statusReceiver, injector);
|
||||
@@ -25911,6 +25923,14 @@ public class PackageManagerService extends IPackageManager.Stub
|
||||
}
|
||||
ps.setStatesOnCrashOrAnr();
|
||||
}
|
||||
|
||||
public void requestChecksums(@NonNull String packageName, boolean includeSplits,
|
||||
@Checksum.Type int optional, @Checksum.Type int required,
|
||||
@Nullable List trustedInstallers, @NonNull IntentSender statusReceiver, int userId,
|
||||
@NonNull Executor executor, @NonNull Handler handler) {
|
||||
requestChecksumsInternal(packageName, includeSplits, optional, required,
|
||||
trustedInstallers, statusReceiver, userId, executor, handler);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -26060,8 +26080,8 @@ public class PackageManagerService extends IPackageManager.Stub
|
||||
if (!SecurityLog.isLoggingEnabled()) {
|
||||
return;
|
||||
}
|
||||
mProcessLoggingHandler.logAppProcessStart(mContext, this, apkFile, packageName, processName,
|
||||
uid, seinfo, pid);
|
||||
mProcessLoggingHandler.logAppProcessStart(mContext, mPmInternal, apkFile, packageName,
|
||||
processName, uid, seinfo, pid);
|
||||
}
|
||||
|
||||
public CompilerStats.PackageStats getCompilerPackageStats(String pkgName) {
|
||||
|
||||
@@ -26,13 +26,12 @@ import android.content.Intent;
|
||||
import android.content.IntentSender;
|
||||
import android.content.pm.ApkChecksum;
|
||||
import android.content.pm.Checksum;
|
||||
import android.content.pm.IPackageManager;
|
||||
import android.content.pm.PackageManagerInternal;
|
||||
import android.os.Bundle;
|
||||
import android.os.Handler;
|
||||
import android.os.HandlerExecutor;
|
||||
import android.os.IBinder;
|
||||
import android.os.Message;
|
||||
import android.os.Parcelable;
|
||||
import android.os.RemoteException;
|
||||
import android.text.TextUtils;
|
||||
import android.util.ArrayMap;
|
||||
import android.util.Slog;
|
||||
@@ -42,12 +41,11 @@ import com.android.internal.os.BackgroundThread;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.Executor;
|
||||
|
||||
public final class ProcessLoggingHandler extends Handler {
|
||||
private static final String TAG = "ProcessLoggingHandler";
|
||||
|
||||
private static final int LOG_APP_PROCESS_START_MSG = 1;
|
||||
|
||||
private static final int CHECKSUM_TYPE = Checksum.TYPE_WHOLE_SHA256;
|
||||
|
||||
static class LoggingInfo {
|
||||
@@ -55,6 +53,9 @@ public final class ProcessLoggingHandler extends Handler {
|
||||
public List<Bundle> pendingLogEntries = new ArrayList<>();
|
||||
}
|
||||
|
||||
// Executor to handle checksum calculations.
|
||||
private final Executor mExecutor = new HandlerExecutor(this);
|
||||
|
||||
// Apk path to logging info map.
|
||||
private final ArrayMap<String, LoggingInfo> mLoggingInfo = new ArrayMap<>();
|
||||
|
||||
@@ -62,25 +63,7 @@ public final class ProcessLoggingHandler extends Handler {
|
||||
super(BackgroundThread.getHandler().getLooper());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleMessage(Message msg) {
|
||||
switch (msg.what) {
|
||||
case LOG_APP_PROCESS_START_MSG: {
|
||||
Bundle bundle = msg.getData();
|
||||
long startTimestamp = bundle.getLong("startTimestamp");
|
||||
String processName = bundle.getString("processName");
|
||||
int uid = bundle.getInt("uid");
|
||||
String seinfo = bundle.getString("seinfo");
|
||||
int pid = bundle.getInt("pid");
|
||||
String apkHash = bundle.getString("apkHash");
|
||||
SecurityLog.writeEvent(SecurityLog.TAG_APP_PROCESS_START, processName,
|
||||
startTimestamp, uid, pid, seinfo, apkHash);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void logAppProcessStart(Context context, IPackageManager pms, String apkFile,
|
||||
void logAppProcessStart(Context context, PackageManagerInternal pmi, String apkFile,
|
||||
String packageName, String processName, int uid, String seinfo, int pid) {
|
||||
Bundle data = new Bundle();
|
||||
data.putLong("startTimestamp", System.currentTimeMillis());
|
||||
@@ -125,7 +108,7 @@ public final class ProcessLoggingHandler extends Handler {
|
||||
// Request base checksums when first added entry.
|
||||
// Capturing local loggingInfo to still log even if hash was invalidated.
|
||||
try {
|
||||
pms.requestChecksums(packageName, false, 0, CHECKSUM_TYPE, null,
|
||||
pmi.requestChecksums(packageName, false, 0, CHECKSUM_TYPE, null,
|
||||
new IntentSender((IIntentSender) new IIntentSender.Stub() {
|
||||
@Override
|
||||
public void send(int code, Intent intent, String resolvedType,
|
||||
@@ -133,10 +116,10 @@ public final class ProcessLoggingHandler extends Handler {
|
||||
String requiredPermission, Bundle options) {
|
||||
processChecksums(loggingInfo, intent);
|
||||
}
|
||||
}), context.getUserId());
|
||||
} catch (RemoteException e) {
|
||||
Slog.e(TAG, "requestChecksums() failed", e);
|
||||
processChecksums(loggingInfo, null);
|
||||
}), context.getUserId(), mExecutor, this);
|
||||
} catch (Throwable t) {
|
||||
Slog.e(TAG, "requestChecksums() failed", t);
|
||||
enqueueProcessChecksum(loggingInfo, null);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -148,9 +131,16 @@ public final class ProcessLoggingHandler extends Handler {
|
||||
for (ApkChecksum checksum : checksums) {
|
||||
if (checksum.getType() == CHECKSUM_TYPE) {
|
||||
processChecksum(loggingInfo, checksum.getValue());
|
||||
break;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
Slog.e(TAG, "requestChecksums() failed to return SHA256, see logs for details.");
|
||||
processChecksum(loggingInfo, null);
|
||||
}
|
||||
|
||||
void enqueueProcessChecksum(final LoggingInfo loggingInfo, final byte[] hash) {
|
||||
this.post(() -> processChecksum(loggingInfo, null));
|
||||
}
|
||||
|
||||
void processChecksum(final LoggingInfo loggingInfo, final byte[] hash) {
|
||||
@@ -178,22 +168,28 @@ public final class ProcessLoggingHandler extends Handler {
|
||||
|
||||
if (pendingLogEntries != null) {
|
||||
for (Bundle data : pendingLogEntries) {
|
||||
enqueueSecurityLogEvent(data, apkHash);
|
||||
logSecurityLogEvent(data, apkHash);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void enqueueSecurityLogEvent(Bundle data, String apkHash) {
|
||||
data.putString("apkHash", apkHash);
|
||||
|
||||
Message msg = this.obtainMessage(LOG_APP_PROCESS_START_MSG);
|
||||
msg.setData(data);
|
||||
this.sendMessage(msg);
|
||||
}
|
||||
|
||||
void invalidateBaseApkHash(String apkFile) {
|
||||
synchronized (mLoggingInfo) {
|
||||
mLoggingInfo.remove(apkFile);
|
||||
}
|
||||
}
|
||||
|
||||
void enqueueSecurityLogEvent(Bundle data, String apkHash) {
|
||||
this.post(() -> logSecurityLogEvent(data, apkHash));
|
||||
}
|
||||
|
||||
void logSecurityLogEvent(Bundle bundle, String apkHash) {
|
||||
long startTimestamp = bundle.getLong("startTimestamp");
|
||||
String processName = bundle.getString("processName");
|
||||
int uid = bundle.getInt("uid");
|
||||
String seinfo = bundle.getString("seinfo");
|
||||
int pid = bundle.getInt("pid");
|
||||
SecurityLog.writeEvent(SecurityLog.TAG_APP_PROCESS_START, processName,
|
||||
startTimestamp, uid, pid, seinfo, apkHash);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user