DexLogger.java revision 2b0b50d25657078ed22430069ae13cb34eecd9d1
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.internal.annotations.VisibleForTesting;
31import com.android.server.pm.Installer;
32import com.android.server.pm.Installer.InstallerException;
33
34import java.io.File;
35import java.util.Set;
36
37import 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 */
43public 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