Home | History | Annotate | Download | only in pm
      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 
     43     ProcessLoggingHandler() {
     44         super(BackgroundThread.getHandler().getLooper());
     45     }
     46 
     47     @Override
     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 
     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 
     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 
    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