/* * Copyright (C) 2018 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.android.car; import android.annotation.Nullable; import android.annotation.RawRes; import android.car.settings.ICarConfigurationManager; import android.car.settings.SpeedBumpConfiguration; import android.content.Context; import android.util.Log; import com.android.internal.annotations.VisibleForTesting; import org.json.JSONException; import org.json.JSONObject; import java.io.PrintWriter; /** * A service that will look at a default JSON configuration file on the system and parses out its * results. * *

This service will look for the JSON file that is mapped to {@code R.raw.car_config}. If this * value does not exist or is malformed, then this service will not fail; instead, it returns * default values for various configurations. */ public class CarConfigurationService extends ICarConfigurationManager.Stub implements CarServiceBase { private static final String TAG = "CarConfigurationService"; // Keys for accessing data in the parsed JSON related to SpeedBump. @VisibleForTesting static final String SPEED_BUMP_CONFIG_KEY = "SpeedBump"; @VisibleForTesting static final String SPEED_BUMP_ACQUIRED_PERMITS_PER_SECOND_KEY = "acquiredPermitsPerSecond"; @VisibleForTesting static final String SPEED_BUMP_MAX_PERMIT_POOL_KEY = "maxPermitPool"; @VisibleForTesting static final String SPEED_BUMP_PERMIT_FILL_DELAY_KEY = "permitFillDelay"; // Default values for speed bump configuration. @VisibleForTesting static final double DEFAULT_SPEED_BUMP_ACQUIRED_PERMITS_PER_SECOND = 0.5d; @VisibleForTesting static final double DEFAULT_SPEED_BUMP_MAX_PERMIT_POOL = 5d; @VisibleForTesting static final long DEFAULT_SPEED_BUMP_PERMIT_FILL_DELAY = 600L; private final Context mContext; private final JsonReader mJsonReader; @VisibleForTesting @Nullable JSONObject mConfigFile; @Nullable private SpeedBumpConfiguration mSpeedBumpConfiguration; /** * An interface that abstracts away the parsing of a JSON file. This interface allows the * JSON file to be mocked away for testing. */ @VisibleForTesting interface JsonReader { /** * Returns the contents of the JSON file that is pointed to by the given {@code resId} as * a string. * * @param context The current Context. * @param resId The resource id of the JSON file. * @return A string representation of the file or {@code null} if an error occurred. */ @Nullable String jsonFileToString(Context context, @RawRes int resId); } CarConfigurationService(Context context, JsonReader reader) { mContext = context; mJsonReader = reader; } /** * Returns the configuration values for speed bump that is found in the configuration JSON on * the system. If there was an error reading this JSON or the JSON did not contain * speed bump configuration, then default values will be returned. This method does not return * {@code null}. */ @Override public SpeedBumpConfiguration getSpeedBumpConfiguration() { if (mSpeedBumpConfiguration == null) { return getDefaultSpeedBumpConfiguration(); } return mSpeedBumpConfiguration; } @Override public synchronized void init() { String jsonString = mJsonReader.jsonFileToString(mContext, R.raw.car_config); if (jsonString != null) { try { mConfigFile = new JSONObject(jsonString); } catch (JSONException e) { Log.e(TAG, "Error reading JSON file", e); } } mSpeedBumpConfiguration = createSpeedBumpConfiguration(); } @Override public synchronized void release() { mConfigFile = null; mSpeedBumpConfiguration = null; } @Override public void dump(PrintWriter writer) { writer.println("*CarConfigurationService*"); writer.println("Config value initialized: " + (mConfigFile != null)); if (mConfigFile != null) { try { writer.println("Config: " + mConfigFile.toString(/* indentSpaces= */ 2)); } catch (JSONException e) { Log.e(TAG, "Error printing JSON config", e); writer.println("Config: " + mConfigFile); } } writer.println("SpeedBumpConfig initialized: " + (mSpeedBumpConfiguration != null)); if (mSpeedBumpConfiguration != null) { writer.println("SpeedBumpConfig: " + mSpeedBumpConfiguration); } } /** * Reads the configuration for speed bump off of the parsed JSON stored in {@link #mConfigFile}. * If {@code mConfigFile} is {@code null} or a configuration does not exist for speed bump, * then return the default configuration created by {@link #getDefaultSpeedBumpConfiguration()}. */ private SpeedBumpConfiguration createSpeedBumpConfiguration() { if (mConfigFile == null) { return getDefaultSpeedBumpConfiguration(); } try { JSONObject speedBumpJson = mConfigFile.getJSONObject(SPEED_BUMP_CONFIG_KEY); if (speedBumpJson != null) { return new SpeedBumpConfiguration( speedBumpJson.getDouble(SPEED_BUMP_ACQUIRED_PERMITS_PER_SECOND_KEY), speedBumpJson.getDouble(SPEED_BUMP_MAX_PERMIT_POOL_KEY), speedBumpJson.getLong(SPEED_BUMP_PERMIT_FILL_DELAY_KEY)); } } catch (JSONException e) { Log.e(TAG, "Error parsing SpeedBumpConfiguration; returning default values", e); } // If an error is encountered or the JSON does not contain an entry for speed bump // configuration, then return default values. return getDefaultSpeedBumpConfiguration(); } private SpeedBumpConfiguration getDefaultSpeedBumpConfiguration() { return new SpeedBumpConfiguration( DEFAULT_SPEED_BUMP_ACQUIRED_PERMITS_PER_SECOND, DEFAULT_SPEED_BUMP_MAX_PERMIT_POOL, DEFAULT_SPEED_BUMP_PERMIT_FILL_DELAY); } }