blob: 9de17c3f39e4470fac5d7cdf9468122429d739be [file] [log] [blame]
/*
* Copyright (C) 2017 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.storagemonitoring;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.util.Slog;
import com.android.car.CarLog;
import com.android.internal.annotations.VisibleForTesting;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
/**
* Loads wear information from the eMMC sysfs entry points.
* sysfs exposes eMMC lifetime data in /sys/bus/mmc/devices/mmc0:0001/{pre_eol_info|life_time}
* The first file contains the value of the PRE_EOL_INFO register as an hexadecimal string
* The second file contains the values of the LIFE_TIME_EST A and B registers as two hexadecimal
* strings separated by a space.
*/
public class EMmcWearInformationProvider implements WearInformationProvider {
private static File DEFAULT_LIFE_TIME_FILE =
new File("/sys/bus/mmc/devices/mmc0:0001/life_time");
private static File DEFAULT_PRE_EOL_FILE =
new File("/sys/bus/mmc/devices/mmc0:0001/pre_eol_info");
private File mLifetimeFile;
private File mPreEolFile;
public EMmcWearInformationProvider() {
this(DEFAULT_LIFE_TIME_FILE, DEFAULT_PRE_EOL_FILE);
}
@VisibleForTesting
EMmcWearInformationProvider(@NonNull File lifetimeFile, @NonNull File preEolFile) {
mLifetimeFile = lifetimeFile;
mPreEolFile = preEolFile;
}
private String readLineFromFile(File f) {
if (!f.exists() || !f.isFile()) {
Slog.i(CarLog.TAG_STORAGE, f + " does not exist or is not a file");
return null;
}
try {
BufferedReader reader = new BufferedReader(new FileReader(f));
String data = reader.readLine();
reader.close();
return data;
} catch (IOException e) {
Slog.w(CarLog.TAG_STORAGE, f + " cannot be read from", e);
return null;
}
}
@Nullable
@Override
public WearInformation load() {
String lifetimeData = readLineFromFile(mLifetimeFile);
String eolData = readLineFromFile(mPreEolFile);
if ((lifetimeData == null) || (eolData == null)) {
return null;
}
String[] lifetimes = lifetimeData.split(" ");
if (lifetimes.length != 2) {
Slog.w(CarLog.TAG_STORAGE, "lifetime data not in expected format: " + lifetimeData);
return null;
}
// Some kernels already add 0x prefix
if (!eolData.startsWith("0x")) {
eolData = "0x" + eolData;
}
int lifetimeA;
int lifetimeB;
int eol;
try {
lifetimeA = Integer.decode(lifetimes[0]);
lifetimeB = Integer.decode(lifetimes[1]);
eol = Integer.decode(eolData);
} catch (NumberFormatException e) {
Slog.w(CarLog.TAG_STORAGE, "lifetime data not in expected format: " + lifetimeData);
return null;
}
return new WearInformation(convertLifetime(lifetimeA),
convertLifetime(lifetimeB),
adjustEol(eol));
}
}