Home | History | Annotate | Download | only in dex
      1 /*
      2  * Copyright (C) 2017 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.dex;
     18 
     19 import android.content.pm.ApplicationInfo;
     20 import android.content.pm.IPackageManager;
     21 import android.os.RemoteException;
     22 
     23 import android.util.ArraySet;
     24 import android.util.ByteStringUtils;
     25 import android.util.EventLog;
     26 import android.util.PackageUtils;
     27 import android.util.Slog;
     28 
     29 import com.android.internal.annotations.GuardedBy;
     30 import com.android.internal.annotations.VisibleForTesting;
     31 import com.android.server.pm.Installer;
     32 import com.android.server.pm.Installer.InstallerException;
     33 
     34 import java.io.File;
     35 import java.util.Set;
     36 
     37 import static com.android.server.pm.dex.PackageDexUsage.DexUseInfo;
     38 
     39 /**
     40  * This class is responsible for logging data about secondary dex files.
     41  * The data logged includes hashes of the name and content of each file.
     42  */
     43 public class DexLogger implements DexManager.Listener {
     44     private static final String TAG = "DexLogger";
     45 
     46     // Event log tag & subtag used for SafetyNet logging of dynamic
     47     // code loading (DCL) - see b/63927552.
     48     private static final int SNET_TAG = 0x534e4554;
     49     private static final String DCL_SUBTAG = "dcl";
     50 
     51     private final IPackageManager mPackageManager;
     52     private final Object mInstallLock;
     53     @GuardedBy("mInstallLock")
     54     private final Installer mInstaller;
     55 
     56     public static DexManager.Listener getListener(IPackageManager pms,
     57             Installer installer, Object installLock) {
     58         return new DexLogger(pms, installer, installLock);
     59     }
     60 
     61     @VisibleForTesting
     62     /*package*/ DexLogger(IPackageManager pms, Installer installer, Object installLock) {
     63         mPackageManager = pms;
     64         mInstaller = installer;
     65         mInstallLock = installLock;
     66     }
     67 
     68     /**
     69      * Compute and log hashes of the name and content of a secondary dex file.
     70      */
     71     @Override
     72     public void onReconcileSecondaryDexFile(ApplicationInfo appInfo, DexUseInfo dexUseInfo,
     73             String dexPath, int storageFlags) {
     74         int ownerUid = appInfo.uid;
     75 
     76         byte[] hash = null;
     77         synchronized(mInstallLock) {
     78             try {
     79                 hash = mInstaller.hashSecondaryDexFile(dexPath, appInfo.packageName,
     80                         ownerUid, appInfo.volumeUuid, storageFlags);
     81             } catch (InstallerException e) {
     82                 Slog.e(TAG, "Got InstallerException when hashing dex " + dexPath +
     83                         " : " + e.getMessage());
     84             }
     85         }
     86         if (hash == null) {
     87             return;
     88         }
     89 
     90         String dexFileName = new File(dexPath).getName();
     91         String message = PackageUtils.computeSha256Digest(dexFileName.getBytes());
     92         // Valid SHA256 will be 256 bits, 32 bytes.
     93         if (hash.length == 32) {
     94             message = message + ' ' + ByteStringUtils.toHexString(hash);
     95         }
     96 
     97         writeDclEvent(ownerUid, message);
     98 
     99         if (dexUseInfo.isUsedByOtherApps()) {
    100             Set<String> otherPackages = dexUseInfo.getLoadingPackages();
    101             Set<Integer> otherUids = new ArraySet<>(otherPackages.size());
    102             for (String otherPackageName : otherPackages) {
    103                 try {
    104                     int otherUid = mPackageManager.getPackageUid(
    105                         otherPackageName, /*flags*/0, dexUseInfo.getOwnerUserId());
    106                     if (otherUid != -1 && otherUid != ownerUid) {
    107                         otherUids.add(otherUid);
    108                     }
    109                 } catch (RemoteException ignore) {
    110                     // Can't happen, we're local.
    111                 }
    112             }
    113             for (int otherUid : otherUids) {
    114                 writeDclEvent(otherUid, message);
    115             }
    116         }
    117     }
    118 
    119     @VisibleForTesting
    120     /*package*/ void writeDclEvent(int uid, String message) {
    121         EventLog.writeEvent(SNET_TAG, DCL_SUBTAG, uid, message);
    122     }
    123 }
    124