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