1 /* 2 * Copyright (C) 2016 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.server.pm; 18 19 import android.app.admin.SecurityLog; 20 import android.content.Intent; 21 import android.os.Bundle; 22 import android.os.Handler; 23 import android.os.Message; 24 25 import com.android.internal.os.BackgroundThread; 26 27 import java.io.File; 28 import java.io.FileInputStream; 29 import java.io.IOException; 30 import java.security.MessageDigest; 31 import java.security.NoSuchAlgorithmException; 32 import java.util.HashMap; 33 import android.util.Slog; 34 35 public final class ProcessLoggingHandler extends Handler { 36 37 private static final String TAG = "ProcessLoggingHandler"; 38 static final int LOG_APP_PROCESS_START_MSG = 1; 39 static final int INVALIDATE_BASE_APK_HASH_MSG = 2; 40 41 private final HashMap<String, String> mProcessLoggingBaseApkHashes = new HashMap(); 42 ProcessLoggingHandler()43 ProcessLoggingHandler() { 44 super(BackgroundThread.getHandler().getLooper()); 45 } 46 47 @Override handleMessage(Message msg)48 public void handleMessage(Message msg) { 49 switch (msg.what) { 50 case LOG_APP_PROCESS_START_MSG: { 51 Bundle bundle = msg.getData(); 52 String processName = bundle.getString("processName"); 53 int uid = bundle.getInt("uid"); 54 String seinfo = bundle.getString("seinfo"); 55 String apkFile = bundle.getString("apkFile"); 56 int pid = bundle.getInt("pid"); 57 long startTimestamp = bundle.getLong("startTimestamp"); 58 String apkHash = computeStringHashOfApk(apkFile); 59 SecurityLog.writeEvent(SecurityLog.TAG_APP_PROCESS_START, processName, 60 startTimestamp, uid, pid, seinfo, apkHash); 61 break; 62 } 63 case INVALIDATE_BASE_APK_HASH_MSG: { 64 Bundle bundle = msg.getData(); 65 mProcessLoggingBaseApkHashes.remove(bundle.getString("apkFile")); 66 break; 67 } 68 } 69 } 70 invalidateProcessLoggingBaseApkHash(String apkPath)71 void invalidateProcessLoggingBaseApkHash(String apkPath) { 72 Bundle data = new Bundle(); 73 data.putString("apkFile", apkPath); 74 Message msg = obtainMessage(INVALIDATE_BASE_APK_HASH_MSG); 75 msg.setData(data); 76 sendMessage(msg); 77 } 78 computeStringHashOfApk(String apkFile)79 private String computeStringHashOfApk(String apkFile) { 80 if (apkFile == null) { 81 return "No APK"; 82 } 83 String apkHash = mProcessLoggingBaseApkHashes.get(apkFile); 84 if (apkHash == null) { 85 try { 86 byte[] hash = computeHashOfApkFile(apkFile); 87 StringBuilder sb = new StringBuilder(); 88 for (int i = 0; i < hash.length; i++) { 89 sb.append(String.format("%02x", hash[i])); 90 } 91 apkHash = sb.toString(); 92 mProcessLoggingBaseApkHashes.put(apkFile, apkHash); 93 } catch (IOException | NoSuchAlgorithmException e) { 94 Slog.w(TAG, "computeStringHashOfApk() failed", e); 95 } 96 } 97 return apkHash != null ? apkHash : "Failed to count APK hash"; 98 } 99 computeHashOfApkFile(String packageArchiveLocation)100 private byte[] computeHashOfApkFile(String packageArchiveLocation) 101 throws IOException, NoSuchAlgorithmException { 102 MessageDigest md = MessageDigest.getInstance("SHA-256"); 103 FileInputStream input = new FileInputStream(new File(packageArchiveLocation)); 104 byte[] buffer = new byte[65536]; 105 int size; 106 while ((size = input.read(buffer)) > 0) { 107 md.update(buffer, 0, size); 108 } 109 input.close(); 110 return md.digest(); 111 } 112 } 113