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