1 /* 2 * Copyright (C) 2021 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.telemetry; 18 19 import static android.car.telemetry.CarTelemetryManager.STATUS_ADD_METRICS_CONFIG_ALREADY_EXISTS; 20 import static android.car.telemetry.CarTelemetryManager.STATUS_ADD_METRICS_CONFIG_SUCCEEDED; 21 import static android.car.telemetry.CarTelemetryManager.STATUS_ADD_METRICS_CONFIG_UNKNOWN; 22 import static android.car.telemetry.CarTelemetryManager.STATUS_ADD_METRICS_CONFIG_VERSION_TOO_OLD; 23 24 import android.annotation.NonNull; 25 import android.car.builtin.util.Slogf; 26 import android.car.telemetry.TelemetryProto; 27 import android.util.ArrayMap; 28 import android.util.AtomicFile; 29 30 import com.android.car.CarLog; 31 import com.android.car.telemetry.util.IoUtils; 32 import com.android.internal.annotations.VisibleForTesting; 33 34 import java.io.File; 35 import java.io.IOException; 36 import java.util.ArrayList; 37 import java.util.List; 38 import java.util.Map; 39 40 /** 41 * This class is responsible for storing, retrieving, and deleting {@link 42 * TelemetryProto.MetricsConfig}. All of the methods are blocking so the class should only be 43 * accessed on the telemetry thread. 44 */ 45 public class MetricsConfigStore { 46 @VisibleForTesting 47 static final String METRICS_CONFIG_DIR = "metrics_configs"; 48 49 private final File mConfigDirectory; 50 private Map<String, TelemetryProto.MetricsConfig> mActiveConfigs; 51 MetricsConfigStore(@onNull File rootDirectory)52 public MetricsConfigStore(@NonNull File rootDirectory) { 53 mConfigDirectory = new File(rootDirectory, METRICS_CONFIG_DIR); 54 mConfigDirectory.mkdirs(); 55 mActiveConfigs = new ArrayMap<>(); 56 // TODO(b/197336485): Add expiration date check for MetricsConfig 57 for (File file : mConfigDirectory.listFiles()) { 58 try { 59 TelemetryProto.MetricsConfig config = TelemetryProto.MetricsConfig.parseFrom( 60 new AtomicFile(file).readFully()); 61 mActiveConfigs.put(config.getName(), config); 62 } catch (IOException e) { 63 // TODO(b/197336655): record failure 64 file.delete(); 65 } 66 } 67 } 68 69 /** 70 * Returns all active {@link TelemetryProto.MetricsConfig} from disk. 71 */ 72 @NonNull getActiveMetricsConfigs()73 public List<TelemetryProto.MetricsConfig> getActiveMetricsConfigs() { 74 return new ArrayList<>(mActiveConfigs.values()); 75 } 76 77 /** 78 * Stores the MetricsConfig to disk if it is valid. It checks both config name and version for 79 * validity. 80 * 81 * @param metricsConfig the config to be persisted to disk. 82 * @return {@link android.car.telemetry.CarTelemetryManager.MetricsConfigStatus} status code. 83 */ addMetricsConfig(@onNull TelemetryProto.MetricsConfig metricsConfig)84 public int addMetricsConfig(@NonNull TelemetryProto.MetricsConfig metricsConfig) { 85 // TODO(b/197336485): Check expiration date for MetricsConfig 86 if (metricsConfig.getVersion() <= 0) { 87 return STATUS_ADD_METRICS_CONFIG_VERSION_TOO_OLD; 88 } 89 if (mActiveConfigs.containsKey(metricsConfig.getName())) { 90 int currentVersion = mActiveConfigs.get(metricsConfig.getName()).getVersion(); 91 if (currentVersion > metricsConfig.getVersion()) { 92 return STATUS_ADD_METRICS_CONFIG_VERSION_TOO_OLD; 93 } else if (currentVersion == metricsConfig.getVersion()) { 94 return STATUS_ADD_METRICS_CONFIG_ALREADY_EXISTS; 95 } 96 } 97 mActiveConfigs.put(metricsConfig.getName(), metricsConfig); 98 try { 99 IoUtils.writeProto(mConfigDirectory, metricsConfig.getName(), metricsConfig); 100 } catch (IOException e) { 101 // TODO(b/197336655): record failure 102 Slogf.w(CarLog.TAG_TELEMETRY, "Failed to write metrics config to disk", e); 103 return STATUS_ADD_METRICS_CONFIG_UNKNOWN; 104 } 105 return STATUS_ADD_METRICS_CONFIG_SUCCEEDED; 106 } 107 108 /** 109 * Deletes the MetricsConfig from disk. 110 * 111 * @param metricsConfigName the unique identifier of the metrics config that should be deleted. 112 * @return true for successful removal, false otherwise. 113 */ removeMetricsConfig(@onNull String metricsConfigName)114 public boolean removeMetricsConfig(@NonNull String metricsConfigName) { 115 if (!mActiveConfigs.containsKey(metricsConfigName)) { 116 return false; // no match found, nothing to remove 117 } 118 mActiveConfigs.remove(metricsConfigName); 119 return IoUtils.deleteSilently(mConfigDirectory, metricsConfigName); 120 } 121 122 /** Deletes all MetricsConfigs from disk. */ removeAllMetricsConfigs()123 public void removeAllMetricsConfigs() { 124 mActiveConfigs.clear(); 125 IoUtils.deleteAllSilently(mConfigDirectory); 126 } 127 128 /** Returns whether a MetricsConfig of the same name exists in the store. */ containsConfig(@onNull String metricsConfigName)129 public boolean containsConfig(@NonNull String metricsConfigName) { 130 return mActiveConfigs.containsKey(metricsConfigName); 131 } 132 } 133