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