PackageManagerServiceCompilerMapping.java revision e131dac848cb4d0998e1dee2219382250c71d277
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
17package com.android.server.pm;
18
19import android.os.SystemProperties;
20
21import dalvik.system.DexFile;
22
23/**
24 * Manage (retrieve) mappings from compilation reason to compilation filter.
25 */
26public class PackageManagerServiceCompilerMapping {
27    // Names for compilation reasons.
28    static final String REASON_STRINGS[] = {
29            "first-boot", "boot", "install", "bg-dexopt", "ab-ota", "inactive", "shared"
30    };
31
32    static final int REASON_SHARED_INDEX = 6;
33
34    // Static block to ensure the strings array is of the right length.
35    static {
36        if (PackageManagerService.REASON_LAST + 1 != REASON_STRINGS.length) {
37            throw new IllegalStateException("REASON_STRINGS not correct");
38        }
39        if (!"shared".equals(REASON_STRINGS[REASON_SHARED_INDEX])) {
40            throw new IllegalStateException("REASON_STRINGS not correct because of shared index");
41        }
42    }
43
44    private static String getSystemPropertyName(int reason) {
45        if (reason < 0 || reason >= REASON_STRINGS.length) {
46            throw new IllegalArgumentException("reason " + reason + " invalid");
47        }
48
49        return "pm.dexopt." + REASON_STRINGS[reason];
50    }
51
52    // Load the property for the given reason and check for validity. This will throw an
53    // exception in case the reason or value are invalid.
54    private static String getAndCheckValidity(int reason) {
55        String sysPropName = getSystemPropertyName(reason);
56        String sysPropValue;
57        // TODO: This is a temporary hack to keep marlin booting on aosp/master while we
58        // figure out how to deal with these system properties that currently appear on
59        // vendor.
60        if ("pm.dexopt.inactive".equals(sysPropName)) {
61            sysPropValue = "verify";
62        } else if ("pm.dexopt.shared".equals(sysPropName)) {
63            sysPropValue = "speed";
64        } else {
65            sysPropValue = SystemProperties.get(sysPropName);
66        }
67        if (sysPropValue == null || sysPropValue.isEmpty() ||
68                !DexFile.isValidCompilerFilter(sysPropValue)) {
69            throw new IllegalStateException("Value \"" + sysPropValue +"\" not valid "
70                    + "(reason " + REASON_STRINGS[reason] + ")");
71        } else if (!isFilterAllowedForReason(reason, sysPropValue)) {
72            throw new IllegalStateException("Value \"" + sysPropValue +"\" not allowed "
73                    + "(reason " + REASON_STRINGS[reason] + ")");
74        }
75
76        return sysPropValue;
77    }
78
79    private static boolean isFilterAllowedForReason(int reason, String filter) {
80        return reason != REASON_SHARED_INDEX || !DexFile.isProfileGuidedCompilerFilter(filter);
81    }
82
83    // Check that the properties are set and valid.
84    // Note: this is done in a separate method so this class can be statically initialized.
85    static void checkProperties() {
86        // We're gonna check all properties and collect the exceptions, so we can give a general
87        // overview. Store the exceptions here.
88        RuntimeException toThrow = null;
89
90        for (int reason = 0; reason <= PackageManagerService.REASON_LAST; reason++) {
91            try {
92                // Check that the system property name is legal.
93                String sysPropName = getSystemPropertyName(reason);
94                if (sysPropName == null || sysPropName.isEmpty()) {
95                    throw new IllegalStateException("Reason system property name \"" +
96                            sysPropName +"\" for reason " + REASON_STRINGS[reason]);
97                }
98
99                // Check validity, ignore result.
100                getAndCheckValidity(reason);
101            } catch (Exception exc) {
102                if (toThrow == null) {
103                    toThrow = new IllegalStateException("PMS compiler filter settings are bad.");
104                }
105                toThrow.addSuppressed(exc);
106            }
107        }
108
109        if (toThrow != null) {
110            throw toThrow;
111        }
112    }
113
114    public static String getCompilerFilterForReason(int reason) {
115        return getAndCheckValidity(reason);
116    }
117
118    /**
119     * Return the default compiler filter for compilation.
120     *
121     * We derive that from the traditional "dalvik.vm.dex2oat-filter" property and just make
122     * sure this isn't profile-guided. Returns "speed" in case of invalid (or missing) values.
123     */
124    public static String getDefaultCompilerFilter() {
125        String value = SystemProperties.get("dalvik.vm.dex2oat-filter");
126        if (value == null || value.isEmpty()) {
127            return "speed";
128        }
129
130        if (!DexFile.isValidCompilerFilter(value) ||
131                DexFile.isProfileGuidedCompilerFilter(value)) {
132            return "speed";
133        }
134
135        return value;
136    }
137}
138