| /* |
| * Copyright (C) 2016 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.pm; |
| |
| import android.app.admin.SecurityLog; |
| import android.content.Intent; |
| import android.os.Bundle; |
| import android.os.Handler; |
| import android.os.Message; |
| |
| import com.android.internal.os.BackgroundThread; |
| |
| import java.io.File; |
| import java.io.FileInputStream; |
| import java.io.IOException; |
| import java.security.MessageDigest; |
| import java.security.NoSuchAlgorithmException; |
| import java.util.HashMap; |
| import android.util.Slog; |
| |
| public final class ProcessLoggingHandler extends Handler { |
| |
| private static final String TAG = "ProcessLoggingHandler"; |
| static final int LOG_APP_PROCESS_START_MSG = 1; |
| static final int INVALIDATE_BASE_APK_HASH_MSG = 2; |
| |
| private final HashMap<String, String> mProcessLoggingBaseApkHashes = new HashMap(); |
| |
| ProcessLoggingHandler() { |
| super(BackgroundThread.getHandler().getLooper()); |
| } |
| |
| @Override |
| public void handleMessage(Message msg) { |
| switch (msg.what) { |
| case LOG_APP_PROCESS_START_MSG: { |
| Bundle bundle = msg.getData(); |
| String processName = bundle.getString("processName"); |
| int uid = bundle.getInt("uid"); |
| String seinfo = bundle.getString("seinfo"); |
| String apkFile = bundle.getString("apkFile"); |
| int pid = bundle.getInt("pid"); |
| long startTimestamp = bundle.getLong("startTimestamp"); |
| String apkHash = computeStringHashOfApk(apkFile); |
| SecurityLog.writeEvent(SecurityLog.TAG_APP_PROCESS_START, processName, |
| startTimestamp, uid, pid, seinfo, apkHash); |
| break; |
| } |
| case INVALIDATE_BASE_APK_HASH_MSG: { |
| Bundle bundle = msg.getData(); |
| mProcessLoggingBaseApkHashes.remove(bundle.getString("apkFile")); |
| break; |
| } |
| } |
| } |
| |
| void invalidateProcessLoggingBaseApkHash(String apkPath) { |
| Bundle data = new Bundle(); |
| data.putString("apkFile", apkPath); |
| Message msg = obtainMessage(INVALIDATE_BASE_APK_HASH_MSG); |
| msg.setData(data); |
| sendMessage(msg); |
| } |
| |
| private String computeStringHashOfApk(String apkFile) { |
| if (apkFile == null) { |
| return "No APK"; |
| } |
| String apkHash = mProcessLoggingBaseApkHashes.get(apkFile); |
| if (apkHash == null) { |
| try { |
| byte[] hash = computeHashOfApkFile(apkFile); |
| StringBuilder sb = new StringBuilder(); |
| for (int i = 0; i < hash.length; i++) { |
| sb.append(String.format("%02x", hash[i])); |
| } |
| apkHash = sb.toString(); |
| mProcessLoggingBaseApkHashes.put(apkFile, apkHash); |
| } catch (IOException | NoSuchAlgorithmException e) { |
| Slog.w(TAG, "computeStringHashOfApk() failed", e); |
| } |
| } |
| return apkHash != null ? apkHash : "Failed to count APK hash"; |
| } |
| |
| private byte[] computeHashOfApkFile(String packageArchiveLocation) |
| throws IOException, NoSuchAlgorithmException { |
| MessageDigest md = MessageDigest.getInstance("SHA-256"); |
| FileInputStream input = new FileInputStream(new File(packageArchiveLocation)); |
| byte[] buffer = new byte[65536]; |
| int size; |
| while ((size = input.read(buffer)) > 0) { |
| md.update(buffer, 0, size); |
| } |
| input.close(); |
| return md.digest(); |
| } |
| } |