Home | History | Annotate | Download | only in pm
      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 dalvik.system.DexFile;
     22 
     23 /**
     24  * Manage (retrieve) mappings from compilation reason to compilation filter.
     25  */
     26 public class PackageManagerServiceCompilerMapping {
     27     // Names for compilation reasons.
     28     public 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 sysPropValue = SystemProperties.get(getSystemPropertyName(reason));
     56         if (sysPropValue == null || sysPropValue.isEmpty() ||
     57                 !DexFile.isValidCompilerFilter(sysPropValue)) {
     58             throw new IllegalStateException("Value \"" + sysPropValue +"\" not valid "
     59                     + "(reason " + REASON_STRINGS[reason] + ")");
     60         } else if (!isFilterAllowedForReason(reason, sysPropValue)) {
     61             throw new IllegalStateException("Value \"" + sysPropValue +"\" not allowed "
     62                     + "(reason " + REASON_STRINGS[reason] + ")");
     63         }
     64 
     65         return sysPropValue;
     66     }
     67 
     68     private static boolean isFilterAllowedForReason(int reason, String filter) {
     69         return reason != REASON_SHARED_INDEX || !DexFile.isProfileGuidedCompilerFilter(filter);
     70     }
     71 
     72     // Check that the properties are set and valid.
     73     // Note: this is done in a separate method so this class can be statically initialized.
     74     static void checkProperties() {
     75         // We're gonna check all properties and collect the exceptions, so we can give a general
     76         // overview. Store the exceptions here.
     77         RuntimeException toThrow = null;
     78 
     79         for (int reason = 0; reason <= PackageManagerService.REASON_LAST; reason++) {
     80             try {
     81                 // Check that the system property name is legal.
     82                 String sysPropName = getSystemPropertyName(reason);
     83                 if (sysPropName == null || sysPropName.isEmpty()) {
     84                     throw new IllegalStateException("Reason system property name \"" +
     85                             sysPropName +"\" for reason " + REASON_STRINGS[reason]);
     86                 }
     87 
     88                 // Check validity, ignore result.
     89                 getAndCheckValidity(reason);
     90             } catch (Exception exc) {
     91                 if (toThrow == null) {
     92                     toThrow = new IllegalStateException("PMS compiler filter settings are bad.");
     93                 }
     94                 toThrow.addSuppressed(exc);
     95             }
     96         }
     97 
     98         if (toThrow != null) {
     99             throw toThrow;
    100         }
    101     }
    102 
    103     public static String getCompilerFilterForReason(int reason) {
    104         return getAndCheckValidity(reason);
    105     }
    106 
    107     /**
    108      * Return the default compiler filter for compilation.
    109      *
    110      * We derive that from the traditional "dalvik.vm.dex2oat-filter" property and just make
    111      * sure this isn't profile-guided. Returns "speed" in case of invalid (or missing) values.
    112      */
    113     public static String getDefaultCompilerFilter() {
    114         String value = SystemProperties.get("dalvik.vm.dex2oat-filter");
    115         if (value == null || value.isEmpty()) {
    116             return "speed";
    117         }
    118 
    119         if (!DexFile.isValidCompilerFilter(value) ||
    120                 DexFile.isProfileGuidedCompilerFilter(value)) {
    121             return "speed";
    122         }
    123 
    124         return value;
    125     }
    126 
    127     public static String getReasonName(int reason) {
    128         if (reason == PackageManagerService.REASON_UNKNOWN) {
    129             return "unknown";
    130         }
    131         if (reason < 0 || reason >= REASON_STRINGS.length) {
    132             throw new IllegalArgumentException("reason " + reason + " invalid");
    133         }
    134         return REASON_STRINGS[reason];
    135     }
    136 }
    137