Merge "Restorecon new vndservice_contexts file." into oc-dev
diff --git a/debuggerd/debuggerd_test.cpp b/debuggerd/debuggerd_test.cpp
index 1befcb1..fa2838e 100644
--- a/debuggerd/debuggerd_test.cpp
+++ b/debuggerd/debuggerd_test.cpp
@@ -479,6 +479,7 @@
err(1, "failed to drop ambient capabilities");
}
+ pthread_setname_np(pthread_self(), "thread_name");
raise(SIGSYS);
});
@@ -492,6 +493,7 @@
FinishIntercept(&intercept_result);
ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
ConsumeFd(std::move(output_fd), &result);
+ ASSERT_MATCH(result, R"(name: thread_name\s+>>> .+debuggerd_test(32|64) <<<)");
ASSERT_MATCH(result, R"(#00 pc [0-9a-f]+\s+ /system/lib)" ARCH_SUFFIX R"(/libc.so \(tgkill)");
}
diff --git a/fs_mgr/fs_mgr_avb.cpp b/fs_mgr/fs_mgr_avb.cpp
index a762038..7512eb9 100644
--- a/fs_mgr/fs_mgr_avb.cpp
+++ b/fs_mgr/fs_mgr_avb.cpp
@@ -390,10 +390,12 @@
continue;
}
- // Ensures that hashtree descriptor is either in /vbmeta or in
+ // Ensures that hashtree descriptor is in /vbmeta or /boot or in
// the same partition for verity setup.
std::string vbmeta_partition_name(verify_data.vbmeta_images[i].partition_name);
- if (vbmeta_partition_name != "vbmeta" && vbmeta_partition_name != partition_name) {
+ if (vbmeta_partition_name != "vbmeta" &&
+ vbmeta_partition_name != "boot" && // for legacy device to append top-level vbmeta
+ vbmeta_partition_name != partition_name) {
LWARNING << "Skip vbmeta image at " << verify_data.vbmeta_images[i].partition_name
<< " for partition: " << partition_name.c_str();
continue;
diff --git a/fs_mgr/fs_mgr_avb_ops.cpp b/fs_mgr/fs_mgr_avb_ops.cpp
index 2c14c9b..8e49663 100644
--- a/fs_mgr/fs_mgr_avb_ops.cpp
+++ b/fs_mgr/fs_mgr_avb_ops.cpp
@@ -39,7 +39,28 @@
#include "fs_mgr_avb_ops.h"
#include "fs_mgr_priv.h"
-static struct fstab* fs_mgr_fstab = nullptr;
+static std::string fstab_by_name_prefix;
+
+static std::string extract_by_name_prefix(struct fstab* fstab) {
+ // In AVB, we can assume that there's an entry for the /misc mount
+ // point in the fstab file and use that to get the device file for
+ // the misc partition. The device needs not to have an actual /misc
+ // partition. Then returns the prefix by removing the trailing "misc":
+ //
+ // - /dev/block/platform/soc.0/7824900.sdhci/by-name/misc ->
+ // - /dev/block/platform/soc.0/7824900.sdhci/by-name/
+
+ struct fstab_rec* fstab_entry = fs_mgr_get_entry_for_mount_point(fstab, "/misc");
+ if (fstab_entry == nullptr) {
+ LERROR << "/misc mount point not found in fstab";
+ return "";
+ }
+
+ std::string full_path(fstab_entry->blk_device);
+ size_t end_slash = full_path.find_last_of("/");
+
+ return full_path.substr(0, end_slash + 1);
+}
static AvbIOResult read_from_partition(AvbOps* ops ATTRIBUTE_UNUSED, const char* partition,
int64_t offset, size_t num_bytes, void* buffer,
@@ -49,30 +70,14 @@
// for partitions having 'slotselect' optin in fstab file, but it
// won't be appended to the mount point.
//
- // In AVB, we can assume that there's an entry for the /misc mount
- // point and use that to get the device file for the misc partition.
- // From there we'll assume that a by-name scheme is used
- // so we can just replace the trailing "misc" by the given
- // |partition|, e.g.
+ // Appends |partition| to the fstab_by_name_prefix, which is obtained
+ // by removing the trailing "misc" from the device file of /misc mount
+ // point. e.g.,
//
- // - /dev/block/platform/soc.0/7824900.sdhci/by-name/misc ->
+ // - /dev/block/platform/soc.0/7824900.sdhci/by-name/ ->
// - /dev/block/platform/soc.0/7824900.sdhci/by-name/system_a
- struct fstab_rec* fstab_entry = fs_mgr_get_entry_for_mount_point(fs_mgr_fstab, "/misc");
-
- if (fstab_entry == nullptr) {
- LERROR << "/misc mount point not found in fstab";
- return AVB_IO_RESULT_ERROR_IO;
- }
-
- std::string partition_name(partition);
- std::string path(fstab_entry->blk_device);
- // Replaces the last field of device file if it's not misc.
- if (!android::base::StartsWith(partition_name, "misc")) {
- size_t end_slash = path.find_last_of("/");
- std::string by_name_prefix(path.substr(0, end_slash + 1));
- path = by_name_prefix + partition_name;
- }
+ std::string path = fstab_by_name_prefix + partition;
// Ensures the device path (a symlink created by init) is ready to
// access. fs_mgr_test_access() will test a few iterations if the
@@ -168,8 +173,8 @@
AvbOps* fs_mgr_dummy_avb_ops_new(struct fstab* fstab) {
AvbOps* ops;
- // Assigns the fstab to the static variable for later use.
- fs_mgr_fstab = fstab;
+ fstab_by_name_prefix = extract_by_name_prefix(fstab);
+ if (fstab_by_name_prefix.empty()) return nullptr;
ops = (AvbOps*)calloc(1, sizeof(AvbOps));
if (ops == nullptr) {
diff --git a/init/README.md b/init/README.md
index e66ade2..822d81e 100644
--- a/init/README.md
+++ b/init/README.md
@@ -198,6 +198,13 @@
is in the class "default" if one is not specified via the
class option. Additional classnames beyond the (required) first
one are used to group services.
+`animation class`
+> 'animation' class should include all services necessary for both
+ boot animation and shutdown animation. As these services can be
+ launched very early during bootup and can run until the last stage
+ of shutdown, access to /data partition is not guaranteed. These
+ services can check files under /data but it should not keep files opened
+ and should work when /data is not available.
`onrestart`
> Execute a Command (see below) when service restarts.
diff --git a/init/builtins.cpp b/init/builtins.cpp
index 64a2d82..75b3c61 100644
--- a/init/builtins.cpp
+++ b/init/builtins.cpp
@@ -919,8 +919,14 @@
if (!is_file_crypto()) {
return 0;
}
- return e4crypt_create_device_key(args[1].c_str(),
- do_installkeys_ensure_dir_exists);
+ auto unencrypted_dir = args[1] + e4crypt_unencrypted_folder;
+ if (do_installkeys_ensure_dir_exists(unencrypted_dir.c_str())) {
+ PLOG(ERROR) << "Failed to create " << unencrypted_dir;
+ return -1;
+ }
+ std::vector<std::string> exec_args = {"exec", "/system/bin/vdc", "--wait", "cryptfs",
+ "enablefilecrypto"};
+ return do_exec(exec_args);
}
static int do_init_user0(const std::vector<std::string>& args) {
diff --git a/init/reboot.cpp b/init/reboot.cpp
index e34abdb..62e5c85 100644
--- a/init/reboot.cpp
+++ b/init/reboot.cpp
@@ -26,6 +26,7 @@
#include <sys/wait.h>
#include <memory>
+#include <set>
#include <string>
#include <thread>
#include <vector>
@@ -41,6 +42,7 @@
#include <logwrap/logwrap.h>
#include "log.h"
+#include "property_service.h"
#include "reboot.h"
#include "service.h"
#include "util.h"
@@ -248,8 +250,9 @@
flags);
} else {
umountDone = false;
- PLOG(WARNING) << StringPrintf("cannot umount %s, flags:0x%x",
- entry.mnt_fsname().c_str(), flags);
+ PLOG(WARNING) << StringPrintf("cannot umount %s, mnt_dir %s, flags:0x%x",
+ entry.mnt_fsname().c_str(),
+ entry.mnt_dir().c_str(), flags);
}
}
}
@@ -351,26 +354,40 @@
}
LOG(INFO) << "Shutdown timeout: " << shutdownTimeout;
- static const constexpr char* shutdown_critical_services[] = {"vold", "watchdogd"};
- for (const char* name : shutdown_critical_services) {
- Service* s = ServiceManager::GetInstance().FindServiceByName(name);
- if (s == nullptr) {
- LOG(WARNING) << "Shutdown critical service not found:" << name;
- continue;
+ // keep debugging tools until non critical ones are all gone.
+ const std::set<std::string> kill_after_apps{"tombstoned", "logd", "adbd"};
+ // watchdogd is a vendor specific component but should be alive to complete shutdown safely.
+ const std::set<std::string> to_starts{"watchdogd", "vold"};
+ ServiceManager::GetInstance().ForEachService([&kill_after_apps, &to_starts](Service* s) {
+ if (kill_after_apps.count(s->name())) {
+ s->SetShutdownCritical();
+ } else if (to_starts.count(s->name())) {
+ s->Start();
+ s->SetShutdownCritical();
}
- s->Start(); // make sure that it is running.
- s->SetShutdownCritical();
+ });
+
+ Service* bootAnim = ServiceManager::GetInstance().FindServiceByName("bootanim");
+ Service* surfaceFlinger = ServiceManager::GetInstance().FindServiceByName("surfaceflinger");
+ if (bootAnim != nullptr && surfaceFlinger != nullptr && surfaceFlinger->IsRunning()) {
+ property_set("service.bootanim.exit", "0");
+ // Could be in the middle of animation. Stop and start so that it can pick
+ // up the right mode.
+ bootAnim->Stop();
+ // start all animation classes if stopped.
+ ServiceManager::GetInstance().ForEachServiceInClass("animation", [](Service* s) {
+ s->Start();
+ s->SetShutdownCritical(); // will not check animation class separately
+ });
+ bootAnim->Start();
+ surfaceFlinger->SetShutdownCritical();
+ bootAnim->SetShutdownCritical();
}
+
// optional shutdown step
// 1. terminate all services except shutdown critical ones. wait for delay to finish
if (shutdownTimeout > 0) {
LOG(INFO) << "terminating init services";
- // tombstoned can write to data when other services are killed. so finish it first.
- static const constexpr char* first_to_kill[] = {"tombstoned"};
- for (const char* name : first_to_kill) {
- Service* s = ServiceManager::GetInstance().FindServiceByName(name);
- if (s != nullptr) s->Stop();
- }
// Ask all services to terminate except shutdown critical ones.
ServiceManager::GetInstance().ForEachService([](Service* s) {
@@ -409,8 +426,8 @@
// minimum safety steps before restarting
// 2. kill all services except ones that are necessary for the shutdown sequence.
- ServiceManager::GetInstance().ForEachService([](Service* s) {
- if (!s->IsShutdownCritical()) s->Stop();
+ ServiceManager::GetInstance().ForEachService([&kill_after_apps](Service* s) {
+ if (!s->IsShutdownCritical() || kill_after_apps.count(s->name())) s->Stop();
});
ServiceManager::GetInstance().ReapAnyOutstandingChildren();
diff --git a/libgrallocusage/GrallocUsageConversion.cpp b/libgrallocusage/GrallocUsageConversion.cpp
index 8164beb..10e728d 100644
--- a/libgrallocusage/GrallocUsageConversion.cpp
+++ b/libgrallocusage/GrallocUsageConversion.cpp
@@ -30,13 +30,17 @@
/* ProducerUsage::CPU_WRITE_OFTEN | */
ProducerUsage::GPU_RENDER_TARGET | ProducerUsage::PROTECTED |
ProducerUsage::CAMERA | ProducerUsage::VIDEO_DECODER |
- ProducerUsage::SENSOR_DIRECT_DATA;
+ ProducerUsage::SENSOR_DIRECT_DATA |
+ /* Private flags may be consumer or producer */
+ GRALLOC_USAGE_PRIVATE_MASK;
constexpr uint64_t CONSUMER_MASK = ConsumerUsage::CPU_READ |
/* ConsumerUsage::CPU_READ_OFTEN | */
ConsumerUsage::GPU_TEXTURE | ConsumerUsage::HWCOMPOSER |
ConsumerUsage::CLIENT_TARGET | ConsumerUsage::CURSOR |
ConsumerUsage::VIDEO_ENCODER | ConsumerUsage::CAMERA |
- ConsumerUsage::RENDERSCRIPT | ConsumerUsage::GPU_DATA_BUFFER;
+ ConsumerUsage::RENDERSCRIPT | ConsumerUsage::GPU_DATA_BUFFER |
+ /* Private flags may be consumer or producer */
+ GRALLOC_USAGE_PRIVATE_MASK;
*producerUsage = static_cast<uint64_t>(usage) & PRODUCER_MASK;
*consumerUsage = static_cast<uint64_t>(usage) & CONSUMER_MASK;
if ((static_cast<uint32_t>(usage) & GRALLOC_USAGE_SW_READ_OFTEN) == GRALLOC_USAGE_SW_READ_OFTEN) {
diff --git a/logd/LogBuffer.cpp b/logd/LogBuffer.cpp
index 1f52d04..bdbe725 100644
--- a/logd/LogBuffer.cpp
+++ b/logd/LogBuffer.cpp
@@ -109,11 +109,11 @@
LogBuffer::LogBuffer(LastLogTimes* times)
: monotonic(android_log_clockid() == CLOCK_MONOTONIC), mTimes(*times) {
- pthread_mutex_init(&mLogElementsLock, NULL);
+ pthread_mutex_init(&mLogElementsLock, nullptr);
log_id_for_each(i) {
- lastLoggedElements[i] = NULL;
- droppedElements[i] = NULL;
+ lastLoggedElements[i] = nullptr;
+ droppedElements[i] = nullptr;
}
init();
@@ -198,7 +198,7 @@
new LogBufferElement(log_id, realtime, uid, pid, tid, msg, len);
if (log_id != LOG_ID_SECURITY) {
int prio = ANDROID_LOG_INFO;
- const char* tag = NULL;
+ const char* tag = nullptr;
if (log_id == LOG_ID_EVENTS) {
tag = tagToName(elem->getTag());
} else {
@@ -224,24 +224,24 @@
//
// State Init
// incoming:
- // dropped = NULL
- // currentLast = NULL;
+ // dropped = nullptr
+ // currentLast = nullptr;
// elem = incoming message
// outgoing:
- // dropped = NULL -> State 0
+ // dropped = nullptr -> State 0
// currentLast = copy of elem
// log elem
// State 0
// incoming:
// count = 0
- // dropped = NULL
+ // dropped = nullptr
// currentLast = copy of last message
// elem = incoming message
// outgoing: if match != DIFFERENT
// dropped = copy of first identical message -> State 1
// currentLast = reference to elem
// break: if match == DIFFERENT
- // dropped = NULL -> State 0
+ // dropped = nullptr -> State 0
// delete copy of last message (incoming currentLast)
// currentLast = copy of elem
// log elem
@@ -268,7 +268,7 @@
// currentLast = reference to elem, sum liblog.
// break: if match == DIFFERENT
// delete dropped
- // dropped = NULL -> State 0
+ // dropped = nullptr -> State 0
// log reference to last held-back (currentLast)
// currentLast = copy of elem
// log elem
@@ -287,7 +287,7 @@
// currentLast = reference to elem
// break: if match == DIFFERENT
// log dropped (chatty message)
- // dropped = NULL -> State 0
+ // dropped = nullptr -> State 0
// log reference to last held-back (currentLast)
// currentLast = copy of elem
// log elem
@@ -352,7 +352,7 @@
} else { // State 1
delete dropped;
}
- droppedElements[log_id] = NULL;
+ droppedElements[log_id] = nullptr;
log(currentLast); // report last message in the series
} else { // State 0
delete currentLast;
@@ -656,7 +656,7 @@
// mLogElementsLock must be held when this function is called.
//
bool LogBuffer::prune(log_id_t id, unsigned long pruneRows, uid_t caller_uid) {
- LogTimeEntry* oldest = NULL;
+ LogTimeEntry* oldest = nullptr;
bool busy = false;
bool clearAll = pruneRows == ULONG_MAX;
@@ -1078,9 +1078,11 @@
return retval;
}
-log_time LogBuffer::flushTo(
- SocketClient* reader, const log_time& start, bool privileged, bool security,
- int (*filter)(const LogBufferElement* element, void* arg), void* arg) {
+log_time LogBuffer::flushTo(SocketClient* reader, const log_time& start,
+ pid_t* lastTid, bool privileged, bool security,
+ int (*filter)(const LogBufferElement* element,
+ void* arg),
+ void* arg) {
LogBufferElementCollection::iterator it;
uid_t uid = reader->getUid();
@@ -1109,9 +1111,6 @@
}
log_time max = start;
- // Help detect if the valid message before is from the same source so
- // we can differentiate chatty filter types.
- pid_t lastTid[LOG_ID_MAX] = { 0 };
for (; it != mLogElements.end(); ++it) {
LogBufferElement* element = *it;
@@ -1139,14 +1138,17 @@
}
}
- bool sameTid = lastTid[element->getLogId()] == element->getTid();
- // Dropped (chatty) immediately following a valid log from the
- // same source in the same log buffer indicates we have a
- // multiple identical squash. chatty that differs source
- // is due to spam filter. chatty to chatty of different
- // source is also due to spam filter.
- lastTid[element->getLogId()] =
- (element->getDropped() && !sameTid) ? 0 : element->getTid();
+ bool sameTid = false;
+ if (lastTid) {
+ sameTid = lastTid[element->getLogId()] == element->getTid();
+ // Dropped (chatty) immediately following a valid log from the
+ // same source in the same log buffer indicates we have a
+ // multiple identical squash. chatty that differs source
+ // is due to spam filter. chatty to chatty of different
+ // source is also due to spam filter.
+ lastTid[element->getLogId()] =
+ (element->getDropped() && !sameTid) ? 0 : element->getTid();
+ }
pthread_mutex_unlock(&mLogElementsLock);
diff --git a/logd/LogBuffer.h b/logd/LogBuffer.h
index fcf6b9a..19d11cb 100644
--- a/logd/LogBuffer.h
+++ b/logd/LogBuffer.h
@@ -115,11 +115,15 @@
int log(log_id_t log_id, log_time realtime, uid_t uid, pid_t pid, pid_t tid,
const char* msg, unsigned short len);
+ // lastTid is an optional context to help detect if the last previous
+ // valid message was from the same source so we can differentiate chatty
+ // filter types (identical or expired)
log_time flushTo(SocketClient* writer, const log_time& start,
+ pid_t* lastTid, // &lastTid[LOG_ID_MAX] or nullptr
bool privileged, bool security,
int (*filter)(const LogBufferElement* element,
- void* arg) = NULL,
- void* arg = NULL);
+ void* arg) = nullptr,
+ void* arg = nullptr);
bool clear(log_id_t id, uid_t uid = AID_ROOT);
unsigned long getSize(log_id_t id);
diff --git a/logd/LogBufferElement.cpp b/logd/LogBufferElement.cpp
index 81356fe..04a620c 100644
--- a/logd/LogBufferElement.cpp
+++ b/logd/LogBufferElement.cpp
@@ -235,7 +235,9 @@
}
iovec[1].iov_len = entry.len;
- log_time retval = reader->sendDatav(iovec, 2) ? FLUSH_ERROR : mRealTime;
+ log_time retval = reader->sendDatav(iovec, 1 + (entry.len != 0))
+ ? FLUSH_ERROR
+ : mRealTime;
if (buffer) free(buffer);
diff --git a/logd/LogReader.cpp b/logd/LogReader.cpp
index 620d4d0..af19279 100644
--- a/logd/LogReader.cpp
+++ b/logd/LogReader.cpp
@@ -182,7 +182,7 @@
} logFindStart(pid, logMask, sequence,
logbuf().isMonotonic() && android::isMonotonic(start));
- logbuf().flushTo(cli, sequence, FlushCommand::hasReadLogs(cli),
+ logbuf().flushTo(cli, sequence, nullptr, FlushCommand::hasReadLogs(cli),
FlushCommand::hasSecurityLogs(cli),
logFindStart.callback, &logFindStart);
diff --git a/logd/LogTimes.cpp b/logd/LogTimes.cpp
index 04e531f..ccc550a 100644
--- a/logd/LogTimes.cpp
+++ b/logd/LogTimes.cpp
@@ -15,6 +15,7 @@
*/
#include <errno.h>
+#include <string.h>
#include <sys/prctl.h>
#include <private/android_logger.h>
@@ -47,7 +48,8 @@
mEnd(log_time(android_log_clockid())) {
mTimeout.tv_sec = timeout / NS_PER_SEC;
mTimeout.tv_nsec = timeout % NS_PER_SEC;
- pthread_cond_init(&threadTriggeredCondition, NULL);
+ memset(mLastTid, 0, sizeof(mLastTid));
+ pthread_cond_init(&threadTriggeredCondition, nullptr);
cleanSkip_Locked();
}
@@ -98,7 +100,7 @@
it++;
}
- me->mClient = NULL;
+ me->mClient = nullptr;
reader.release(client);
}
@@ -122,7 +124,7 @@
SocketClient* client = me->mClient;
if (!client) {
me->error();
- return NULL;
+ return nullptr;
}
LogBuffer& logbuf = me->mReader.logbuf();
@@ -151,12 +153,12 @@
unlock();
if (me->mTail) {
- logbuf.flushTo(client, start, privileged, security, FilterFirstPass,
- me);
+ logbuf.flushTo(client, start, nullptr, privileged, security,
+ FilterFirstPass, me);
me->leadingDropped = true;
}
- start = logbuf.flushTo(client, start, privileged, security,
- FilterSecondPass, me);
+ start = logbuf.flushTo(client, start, me->mLastTid, privileged,
+ security, FilterSecondPass, me);
lock();
@@ -182,7 +184,7 @@
pthread_cleanup_pop(true);
- return NULL;
+ return nullptr;
}
// A first pass to count the number of elements
@@ -281,7 +283,5 @@
}
void LogTimeEntry::cleanSkip_Locked(void) {
- for (log_id_t i = LOG_ID_MIN; i < LOG_ID_MAX; i = (log_id_t)(i + 1)) {
- skipAhead[i] = 0;
- }
+ memset(skipAhead, 0, sizeof(skipAhead));
}
diff --git a/logd/LogTimes.h b/logd/LogTimes.h
index 9a3ddab..ec8252e 100644
--- a/logd/LogTimes.h
+++ b/logd/LogTimes.h
@@ -44,6 +44,7 @@
const unsigned int mLogMask;
const pid_t mPid;
unsigned int skipAhead[LOG_ID_MAX];
+ pid_t mLastTid[LOG_ID_MAX];
unsigned long mCount;
unsigned long mTail;
unsigned long mIndex;
diff --git a/storaged/README.properties b/storaged/README.properties
index 70e6026..2d8397f 100644
--- a/storaged/README.properties
+++ b/storaged/README.properties
@@ -1,6 +1,5 @@
ro.storaged.event.interval # interval storaged scans for IO stats, in seconds
ro.storaged.event.perf_check # check for time spent in event loop, in microseconds
ro.storaged.disk_stats_pub # interval storaged publish disk stats, in seconds
-ro.storaged.emmc_info_pub # interval storaged publish emmc info, in seconds
ro.storaged.uid_io.interval # interval storaged checks Per UID IO usage, in seconds
ro.storaged.uid_io.threshold # Per UID IO usage limit, in bytes
diff --git a/storaged/include/storaged.h b/storaged/include/storaged.h
index bd1391c..b6a0850 100644
--- a/storaged/include/storaged.h
+++ b/storaged/include/storaged.h
@@ -230,7 +230,6 @@
// Periodic chores intervals in seconds
#define DEFAULT_PERIODIC_CHORES_INTERVAL_UNIT ( 60 )
#define DEFAULT_PERIODIC_CHORES_INTERVAL_DISK_STATS_PUBLISH ( 3600 )
-#define DEFAULT_PERIODIC_CHORES_INTERVAL_EMMC_INFO_PUBLISH ( 86400 )
#define DEFAULT_PERIODIC_CHORES_INTERVAL_UID_IO ( 3600 )
#define DEFAULT_PERIODIC_CHORES_INTERVAL_UID_IO_LIMIT (300)
@@ -240,7 +239,6 @@
struct storaged_config {
int periodic_chores_interval_unit;
int periodic_chores_interval_disk_stats_publish;
- int periodic_chores_interval_emmc_info_publish;
int periodic_chores_interval_uid_io;
bool proc_uid_io_available; // whether uid_io is accessible
bool diskstats_available; // whether diskstats is accessible
@@ -253,7 +251,6 @@
storaged_config mConfig;
disk_stats_publisher mDiskStats;
disk_stats_monitor mDsm;
- storage_info_t *info = nullptr;
uid_monitor mUidm;
time_t mStarttime;
public:
@@ -264,9 +261,6 @@
void pause(void) {
sleep(mConfig.periodic_chores_interval_unit);
}
- void set_storage_info(storage_info_t *storage_info) {
- info = storage_info;
- }
time_t get_starttime(void) {
return mStarttime;
diff --git a/storaged/include/storaged_info.h b/storaged/include/storaged_info.h
index cb5b8a8..913c814 100644
--- a/storaged/include/storaged_info.h
+++ b/storaged/include/storaged_info.h
@@ -24,43 +24,42 @@
using namespace std;
-// two characters in string for each byte
-struct str_hex {
- char str[2];
-};
-
class storage_info_t {
protected:
FRIEND_TEST(storaged_test, storage_info_t);
- uint8_t eol; // pre-eol (end of life) information
- uint8_t lifetime_a; // device life time estimation (type A)
- uint8_t lifetime_b; // device life time estimation (type B)
+ uint16_t eol; // pre-eol (end of life) information
+ uint16_t lifetime_a; // device life time estimation (type A)
+ uint16_t lifetime_b; // device life time estimation (type B)
string version; // version string
-public:
void publish();
+public:
+ storage_info_t() : eol(0), lifetime_a(0), lifetime_b(0) {}
virtual ~storage_info_t() {}
- virtual bool init() = 0;
- virtual bool update() = 0;
+ virtual bool report() = 0;
};
class emmc_info_t : public storage_info_t {
private:
- // minimum size of a ext_csd file
- const int EXT_CSD_FILE_MIN_SIZE = 1024;
- // List of interesting offsets
- const size_t EXT_CSD_REV_IDX = 192 * sizeof(str_hex);
- const size_t EXT_PRE_EOL_INFO_IDX = 267 * sizeof(str_hex);
- const size_t EXT_DEVICE_LIFE_TIME_EST_A_IDX = 268 * sizeof(str_hex);
- const size_t EXT_DEVICE_LIFE_TIME_EST_B_IDX = 269 * sizeof(str_hex);
-
- const char* ext_csd_file = "/d/mmc0/mmc0:0001/ext_csd";
- const char* emmc_ver_str[8] = {
- "4.0", "4.1", "4.2", "4.3", "Obsolete", "4.41", "4.5", "5.0"
+ const string emmc_sysfs = "/sys/bus/mmc/devices/mmc0:0001/";
+ const string emmc_debugfs = "/d/mmc0/mmc0:0001/ext_csd";
+ const char* emmc_ver_str[9] = {
+ "4.0", "4.1", "4.2", "4.3", "Obsolete", "4.41", "4.5", "5.0", "5.1"
};
public:
virtual ~emmc_info_t() {}
- bool init();
- bool update();
+ bool report();
+ bool report_sysfs();
+ bool report_debugfs();
};
+class ufs_info_t : public storage_info_t {
+private:
+ const string health_file = "/sys/devices/soc/624000.ufshc/health";
+public:
+ virtual ~ufs_info_t() {}
+ bool report();
+};
+
+void report_storage_health();
+
#endif /* _STORAGED_INFO_H_ */
diff --git a/storaged/main.cpp b/storaged/main.cpp
index e25298b..2f2273d 100644
--- a/storaged/main.cpp
+++ b/storaged/main.cpp
@@ -43,7 +43,6 @@
#include <storaged_utils.h>
storaged_t storaged;
-emmc_info_t emmc_info;
// Function of storaged's main thread
void* storaged_main(void* s) {
@@ -114,10 +113,7 @@
}
if (flag_main_service) { // start main thread
- if (emmc_info.init()) {
- storaged.set_storage_info(&emmc_info);
- }
-
+ report_storage_health();
// Start the main thread of storaged
pthread_t storaged_main_thread;
errno = pthread_create(&storaged_main_thread, NULL, storaged_main, &storaged);
diff --git a/storaged/storaged.cpp b/storaged/storaged.cpp
index 88fbb7a..1770922 100644
--- a/storaged/storaged.cpp
+++ b/storaged/storaged.cpp
@@ -170,6 +170,9 @@
}
void storaged_t::init_battery_service() {
+ if (!mConfig.proc_uid_io_available)
+ return;
+
sp<IBatteryPropertiesRegistrar> battery_properties = get_battery_properties_service();
if (battery_properties == NULL) {
LOG_TO(SYSTEM, WARNING) << "failed to find batteryproperties service";
@@ -203,9 +206,6 @@
mConfig.periodic_chores_interval_disk_stats_publish =
property_get_int32("ro.storaged.disk_stats_pub", DEFAULT_PERIODIC_CHORES_INTERVAL_DISK_STATS_PUBLISH);
- mConfig.periodic_chores_interval_emmc_info_publish =
- property_get_int32("ro.storaged.emmc_info_pub", DEFAULT_PERIODIC_CHORES_INTERVAL_EMMC_INFO_PUBLISH);
-
mConfig.periodic_chores_interval_uid_io =
property_get_int32("ro.storaged.uid_io.interval", DEFAULT_PERIODIC_CHORES_INTERVAL_UID_IO);
@@ -221,12 +221,6 @@
}
}
- if (info && mTimer &&
- (mTimer % mConfig.periodic_chores_interval_emmc_info_publish) == 0) {
- info->update();
- info->publish();
- }
-
if (mConfig.proc_uid_io_available && mTimer &&
(mTimer % mConfig.periodic_chores_interval_uid_io) == 0) {
mUidm.report();
diff --git a/storaged/storaged_info.cpp b/storaged/storaged_info.cpp
index 73d611c..434bd74 100644
--- a/storaged/storaged_info.cpp
+++ b/storaged/storaged_info.cpp
@@ -16,83 +16,169 @@
#define LOG_TAG "storaged"
+#include <stdio.h>
#include <string.h>
#include <android-base/file.h>
-#include <android-base/logging.h>
#include <android-base/parseint.h>
+#include <android-base/logging.h>
+#include <android-base/strings.h>
#include <log/log_event_list.h>
#include "storaged.h"
using namespace std;
-using namespace android;
using namespace android::base;
+void report_storage_health()
+{
+ emmc_info_t mmc;
+ ufs_info_t ufs;
+
+ mmc.report();
+ ufs.report();
+}
+
void storage_info_t::publish()
{
- if (eol == 0 && lifetime_a == 0 && lifetime_b == 0) {
- return;
- }
-
android_log_event_list(EVENTLOGTAG_EMMCINFO)
<< version << eol << lifetime_a << lifetime_b
<< LOG_ID_EVENTS;
}
-bool emmc_info_t::init()
+bool emmc_info_t::report()
+{
+ if (!report_sysfs() && !report_debugfs())
+ return false;
+
+ publish();
+ return true;
+}
+
+bool emmc_info_t::report_sysfs()
{
string buffer;
- if (!ReadFileToString(ext_csd_file, &buffer) ||
- buffer.length() < (size_t)EXT_CSD_FILE_MIN_SIZE) {
+ uint16_t rev = 0;
+
+ if (!ReadFileToString(emmc_sysfs + "rev", &buffer)) {
return false;
}
- string ver_str = buffer.substr(EXT_CSD_REV_IDX, sizeof(str_hex));
- uint8_t ext_csd_rev;
- if (!ParseUint(ver_str, &ext_csd_rev)) {
- LOG_TO(SYSTEM, ERROR) << "Failure on parsing EXT_CSD_REV.";
+ if (sscanf(buffer.c_str(), "0x%hx", &rev) < 1 ||
+ rev < 7 || rev > ARRAY_SIZE(emmc_ver_str)) {
return false;
}
version = "emmc ";
- version += (ext_csd_rev < ARRAY_SIZE(emmc_ver_str)) ?
- emmc_ver_str[ext_csd_rev] : "Unknown";
+ version += emmc_ver_str[rev];
- if (ext_csd_rev < 7) {
+ if (!ReadFileToString(emmc_sysfs + "pre_eol_info", &buffer)) {
return false;
}
- return update();
-}
-
-bool emmc_info_t::update()
-{
- string buffer;
- if (!ReadFileToString(ext_csd_file, &buffer) ||
- buffer.length() < (size_t)EXT_CSD_FILE_MIN_SIZE) {
+ if (sscanf(buffer.c_str(), "%hx", &eol) < 1 || eol == 0) {
return false;
}
- string str = buffer.substr(EXT_PRE_EOL_INFO_IDX, sizeof(str_hex));
- if (!ParseUint(str, &eol)) {
- LOG_TO(SYSTEM, ERROR) << "Failure on parsing EXT_PRE_EOL_INFO.";
+ if (!ReadFileToString(emmc_sysfs + "life_time", &buffer)) {
return false;
}
- str = buffer.substr(EXT_DEVICE_LIFE_TIME_EST_A_IDX, sizeof(str_hex));
- if (!ParseUint(str, &lifetime_a)) {
- LOG_TO(SYSTEM, ERROR)
- << "Failure on parsing EXT_DEVICE_LIFE_TIME_EST_TYP_A.";
- return false;
- }
-
- str = buffer.substr(EXT_DEVICE_LIFE_TIME_EST_B_IDX, sizeof(str_hex));
- if (!ParseUint(str, &lifetime_b)) {
- LOG_TO(SYSTEM, ERROR)
- << "Failure on parsing EXT_DEVICE_LIFE_TIME_EST_TYP_B.";
+ if (sscanf(buffer.c_str(), "0x%hx 0x%hx", &lifetime_a, &lifetime_b) < 2 ||
+ (lifetime_a == 0 && lifetime_b == 0)) {
return false;
}
return true;
}
+
+const size_t EXT_CSD_FILE_MIN_SIZE = 1024;
+/* 2 characters in string for each byte */
+const size_t EXT_CSD_REV_IDX = 192 * 2;
+const size_t EXT_PRE_EOL_INFO_IDX = 267 * 2;
+const size_t EXT_DEVICE_LIFE_TIME_EST_A_IDX = 268 * 2;
+const size_t EXT_DEVICE_LIFE_TIME_EST_B_IDX = 269 * 2;
+
+bool emmc_info_t::report_debugfs()
+{
+ string buffer;
+ uint16_t rev = 0;
+
+ if (!ReadFileToString(emmc_debugfs, &buffer) ||
+ buffer.length() < (size_t)EXT_CSD_FILE_MIN_SIZE) {
+ return false;
+ }
+
+ string str = buffer.substr(EXT_CSD_REV_IDX, 2);
+ if (!ParseUint(str, &rev) ||
+ rev < 7 || rev > ARRAY_SIZE(emmc_ver_str)) {
+ return false;
+ }
+
+ version = "emmc ";
+ version += emmc_ver_str[rev];
+
+ str = buffer.substr(EXT_PRE_EOL_INFO_IDX, 2);
+ if (!ParseUint(str, &eol)) {
+ return false;
+ }
+
+ str = buffer.substr(EXT_DEVICE_LIFE_TIME_EST_A_IDX, 2);
+ if (!ParseUint(str, &lifetime_a)) {
+ return false;
+ }
+
+ str = buffer.substr(EXT_DEVICE_LIFE_TIME_EST_B_IDX, 2);
+ if (!ParseUint(str, &lifetime_b)) {
+ return false;
+ }
+
+ return true;
+}
+
+bool ufs_info_t::report()
+{
+ string buffer;
+ if (!ReadFileToString(health_file, &buffer)) {
+ return false;
+ }
+
+ vector<string> lines = Split(buffer, "\n");
+ if (lines.empty()) {
+ return false;
+ }
+
+ char rev[8];
+ if (sscanf(lines[0].c_str(), "ufs version: 0x%7s\n", rev) < 1) {
+ return false;
+ }
+
+ version = "ufs " + string(rev);
+
+ for (size_t i = 1; i < lines.size(); i++) {
+ char token[32];
+ uint16_t val;
+ int ret;
+ if ((ret = sscanf(lines[i].c_str(),
+ "Health Descriptor[Byte offset 0x%*d]: %31s = 0x%hx",
+ token, &val)) < 2) {
+ continue;
+ }
+
+ if (string(token) == "bPreEOLInfo") {
+ eol = val;
+ } else if (string(token) == "bDeviceLifeTimeEstA") {
+ lifetime_a = val;
+ } else if (string(token) == "bDeviceLifeTimeEstB") {
+ lifetime_b = val;
+ }
+ }
+
+ if (eol == 0 || (lifetime_a == 0 && lifetime_b == 0)) {
+ return false;
+ }
+
+ publish();
+ return true;
+}
+
diff --git a/storaged/tests/storaged_test.cpp b/storaged/tests/storaged_test.cpp
index e335cad..b103ac1 100644
--- a/storaged/tests/storaged_test.cpp
+++ b/storaged/tests/storaged_test.cpp
@@ -29,7 +29,6 @@
#define MMC_DISK_STATS_PATH "/sys/block/mmcblk0/stat"
#define SDA_DISK_STATS_PATH "/sys/block/sda/stat"
-#define EMMC_EXT_CSD_PATH "/d/mmc0/mmc0:0001/ext_csd"
static void pause(uint32_t sec) {
const char* path = "/cache/test";
@@ -58,13 +57,8 @@
const char* DISK_STATS_PATH;
TEST(storaged_test, retvals) {
struct disk_stats stats;
- emmc_info_t info;
memset(&stats, 0, sizeof(struct disk_stats));
- if (info.init()) {
- EXPECT_TRUE(info.update());
- }
-
if (access(MMC_DISK_STATS_PATH, R_OK) >= 0) {
DISK_STATS_PATH = MMC_DISK_STATS_PATH;
} else if (access(SDA_DISK_STATS_PATH, R_OK) >= 0) {
@@ -127,20 +121,6 @@
}
}
-TEST(storaged_test, storage_info_t) {
- emmc_info_t info;
-
- if (access(EMMC_EXT_CSD_PATH, R_OK) >= 0) {
- int ret = info.init();
- if (ret) {
- EXPECT_TRUE(info.version.empty());
- ASSERT_TRUE(info.update());
- // update should put something in info.
- EXPECT_TRUE(info.eol || info.lifetime_a || info.lifetime_b);
- }
- }
-}
-
static double mean(std::deque<uint32_t> nums) {
double sum = 0.0;
for (uint32_t i : nums) {