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