1 /* 2 * Copyright (C) 2018 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.car; 18 19 import android.annotation.Nullable; 20 import android.annotation.RawRes; 21 import android.car.settings.ICarConfigurationManager; 22 import android.car.settings.SpeedBumpConfiguration; 23 import android.content.Context; 24 import android.util.Log; 25 26 import com.android.internal.annotations.VisibleForTesting; 27 28 import org.json.JSONException; 29 import org.json.JSONObject; 30 31 import java.io.PrintWriter; 32 33 /** 34 * A service that will look at a default JSON configuration file on the system and parses out its 35 * results. 36 * 37 * <p>This service will look for the JSON file that is mapped to {@code R.raw.car_config}. If this 38 * value does not exist or is malformed, then this service will not fail; instead, it returns 39 * default values for various configurations. 40 */ 41 public class CarConfigurationService extends ICarConfigurationManager.Stub 42 implements CarServiceBase { 43 private static final String TAG = "CarConfigurationService"; 44 45 // Keys for accessing data in the parsed JSON related to SpeedBump. 46 @VisibleForTesting 47 static final String SPEED_BUMP_CONFIG_KEY = "SpeedBump"; 48 @VisibleForTesting 49 static final String SPEED_BUMP_ACQUIRED_PERMITS_PER_SECOND_KEY = 50 "acquiredPermitsPerSecond"; 51 @VisibleForTesting 52 static final String SPEED_BUMP_MAX_PERMIT_POOL_KEY = "maxPermitPool"; 53 @VisibleForTesting 54 static final String SPEED_BUMP_PERMIT_FILL_DELAY_KEY = "permitFillDelay"; 55 56 // Default values for speed bump configuration. 57 @VisibleForTesting 58 static final double DEFAULT_SPEED_BUMP_ACQUIRED_PERMITS_PER_SECOND = 0.5d; 59 @VisibleForTesting 60 static final double DEFAULT_SPEED_BUMP_MAX_PERMIT_POOL = 5d; 61 @VisibleForTesting 62 static final long DEFAULT_SPEED_BUMP_PERMIT_FILL_DELAY = 600L; 63 64 private final Context mContext; 65 private final JsonReader mJsonReader; 66 67 @VisibleForTesting 68 @Nullable 69 JSONObject mConfigFile; 70 71 @Nullable 72 private SpeedBumpConfiguration mSpeedBumpConfiguration; 73 74 /** 75 * An interface that abstracts away the parsing of a JSON file. This interface allows the 76 * JSON file to be mocked away for testing. 77 */ 78 @VisibleForTesting 79 interface JsonReader { 80 /** 81 * Returns the contents of the JSON file that is pointed to by the given {@code resId} as 82 * a string. 83 * 84 * @param context The current Context. 85 * @param resId The resource id of the JSON file. 86 * @return A string representation of the file or {@code null} if an error occurred. 87 */ 88 @Nullable jsonFileToString(Context context, @RawRes int resId)89 String jsonFileToString(Context context, @RawRes int resId); 90 } 91 CarConfigurationService(Context context, JsonReader reader)92 CarConfigurationService(Context context, JsonReader reader) { 93 mContext = context; 94 mJsonReader = reader; 95 } 96 97 /** 98 * Returns the configuration values for speed bump that is found in the configuration JSON on 99 * the system. If there was an error reading this JSON or the JSON did not contain 100 * speed bump configuration, then default values will be returned. This method does not return 101 * {@code null}. 102 */ 103 @Override getSpeedBumpConfiguration()104 public SpeedBumpConfiguration getSpeedBumpConfiguration() { 105 if (mSpeedBumpConfiguration == null) { 106 return getDefaultSpeedBumpConfiguration(); 107 } 108 return mSpeedBumpConfiguration; 109 } 110 111 @Override init()112 public synchronized void init() { 113 String jsonString = mJsonReader.jsonFileToString(mContext, R.raw.car_config); 114 if (jsonString != null) { 115 try { 116 mConfigFile = new JSONObject(jsonString); 117 } catch (JSONException e) { 118 Log.e(TAG, "Error reading JSON file", e); 119 } 120 } 121 122 mSpeedBumpConfiguration = createSpeedBumpConfiguration(); 123 } 124 125 @Override release()126 public synchronized void release() { 127 mConfigFile = null; 128 mSpeedBumpConfiguration = null; 129 } 130 131 @Override dump(PrintWriter writer)132 public void dump(PrintWriter writer) { 133 writer.println("*CarConfigurationService*"); 134 writer.println("Config value initialized: " + (mConfigFile != null)); 135 if (mConfigFile != null) { 136 try { 137 writer.println("Config: " + mConfigFile.toString(/* indentSpaces= */ 2)); 138 } catch (JSONException e) { 139 Log.e(TAG, "Error printing JSON config", e); 140 writer.println("Config: " + mConfigFile); 141 } 142 } 143 144 writer.println("SpeedBumpConfig initialized: " + (mSpeedBumpConfiguration != null)); 145 if (mSpeedBumpConfiguration != null) { 146 writer.println("SpeedBumpConfig: " + mSpeedBumpConfiguration); 147 } 148 } 149 150 /** 151 * Reads the configuration for speed bump off of the parsed JSON stored in {@link #mConfigFile}. 152 * If {@code mConfigFile} is {@code null} or a configuration does not exist for speed bump, 153 * then return the default configuration created by {@link #getDefaultSpeedBumpConfiguration()}. 154 */ createSpeedBumpConfiguration()155 private SpeedBumpConfiguration createSpeedBumpConfiguration() { 156 if (mConfigFile == null) { 157 return getDefaultSpeedBumpConfiguration(); 158 } 159 160 try { 161 JSONObject speedBumpJson = mConfigFile.getJSONObject(SPEED_BUMP_CONFIG_KEY); 162 163 if (speedBumpJson != null) { 164 return new SpeedBumpConfiguration( 165 speedBumpJson.getDouble(SPEED_BUMP_ACQUIRED_PERMITS_PER_SECOND_KEY), 166 speedBumpJson.getDouble(SPEED_BUMP_MAX_PERMIT_POOL_KEY), 167 speedBumpJson.getLong(SPEED_BUMP_PERMIT_FILL_DELAY_KEY)); 168 } 169 } catch (JSONException e) { 170 Log.e(TAG, "Error parsing SpeedBumpConfiguration; returning default values", e); 171 } 172 173 // If an error is encountered or the JSON does not contain an entry for speed bump 174 // configuration, then return default values. 175 return getDefaultSpeedBumpConfiguration(); 176 } 177 getDefaultSpeedBumpConfiguration()178 private SpeedBumpConfiguration getDefaultSpeedBumpConfiguration() { 179 return new SpeedBumpConfiguration( 180 DEFAULT_SPEED_BUMP_ACQUIRED_PERMITS_PER_SECOND, 181 DEFAULT_SPEED_BUMP_MAX_PERMIT_POOL, 182 DEFAULT_SPEED_BUMP_PERMIT_FILL_DELAY); 183 } 184 } 185