storage daemon: handle flag info file update

1, when the persistent flag value is updated, mark in flag info file
that this flag has override.

2, when querying a persistent flag, also return the flag info along with
flag value.

Bug: b/312444587
Test: atest aconfigd_test
Flag: enable_aconfig_storage_daemon
Change-Id: I98efe114013e775b853cbfe6e5dba8d6212a3f20
diff --git a/aconfigd/aconfigd.cpp b/aconfigd/aconfigd.cpp
index eab1a34..e54fc49 100644
--- a/aconfigd/aconfigd.cpp
+++ b/aconfigd/aconfigd.cpp
@@ -33,18 +33,11 @@
 using storage_records_pb = android::aconfig_storage_metadata::storage_files;
 using storage_record_pb = android::aconfig_storage_metadata::storage_file_info;
 using namespace android::base;
+using namespace aconfig_storage;
 
 namespace android {
 namespace aconfigd {
 
-/// Persistent storage records pb file full path
-static constexpr char kPersistentStorageRecordsFileName[] =
-    "/metadata/aconfig/persistent_storage_file_records.pb";
-
-/// Persistent storage records pb file full path
-static constexpr char kAvailableStorageRecordsFileName[] =
-    "/metadata/aconfig/boot/available_storage_file_records.pb";
-
 /// In memory data structure for storage file locations for each container
 struct StorageRecord {
   int version;
@@ -79,41 +72,6 @@
 
 namespace {
 
-/// Read persistent aconfig storage records pb file
-Result<storage_records_pb> ReadStorageRecordsPb(const std::string& pb_file) {
-  auto records = storage_records_pb();
-  if (FileExists(pb_file)) {
-    auto content = std::string();
-    if (!ReadFileToString(pb_file, &content)) {
-      return ErrnoError() << "ReadFileToString failed";
-    }
-
-    if (!records.ParseFromString(content)) {
-      return ErrnoError() << "Unable to parse storage records protobuf";
-    }
-  }
-  return records;
-}
-
-/// Write aconfig storage records protobuf to file
-Result<void> WriteStorageRecordsPbToFile(const storage_records_pb& records_pb,
-                                         const std::string& file_name) {
-  auto content = std::string();
-  if (!records_pb.SerializeToString(&content)) {
-    return ErrnoError() << "Unable to serialize storage records protobuf";
-  }
-
-  if (!WriteStringToFile(content, file_name)) {
-    return ErrnoError() << "WriteStringToFile failed";
-  }
-
-  if (chmod(file_name.c_str(), 0644) == -1) {
-    return ErrnoError() << "chmod failed";
-  };
-
-  return {};
-}
-
 /// Write in memory aconfig storage records to the persistent pb file
 Result<void> WritePersistentStorageRecordsToFile() {
   auto records_pb = storage_records_pb();
@@ -215,15 +173,14 @@
                      << copy_result.error();
     }
 
-    auto version_result = aconfig_storage::get_storage_file_version(value_file);
-    if (!version_result.ok()) {
-      return Error() << "Failed to get storage version: " << version_result.error();
+    auto version = get_storage_file_version(value_file);
+    if (!version.ok()) {
+      return Error() << "Failed to get storage version: " << version.error();
     }
 
     // create flag info file
     auto flag_info_file = std::string("/metadata/aconfig/flags/") + container + ".info";
-    auto create_result = aconfig_storage::create_flag_info(
-        package_file, flag_file, flag_info_file);
+    auto create_result = create_flag_info(package_file, flag_file, flag_info_file);
     if (!create_result.ok()) {
       return Error() << "Failed to create flag info file for container " << container
                      << ": " << create_result.error();
@@ -231,7 +188,7 @@
 
     // add to in memory storage file records
     auto& record = persist_storage_records[container];
-    record.version = *version_result;
+    record.version = *version;
     record.container = container;
     record.package_map = package_file;
     record.flag_map = flag_file;
@@ -265,21 +222,20 @@
   }
 
   for (auto& entry : records_pb->files()) {
-    auto mapped_file = aconfig_storage::get_mapped_file(
-        entry.container(), aconfig_storage::StorageFileType::package_map);
+    auto mapped_file = get_mapped_file(entry.container(), StorageFileType::package_map);
     if (!mapped_file.ok()) {
       return Error() << "Failed to map file for container " << entry.container()
                      << ": " << mapped_file.error();
     }
 
-    auto offset = aconfig_storage::get_package_read_context(*mapped_file, package);
-    if (!offset.ok()) {
+    auto context= get_package_read_context(*mapped_file, package);
+    if (!context.ok()) {
       return Error() << "Failed to get offset for package " << package
                      << " from package map of " << entry.container() << " :"
-                     << offset.error();
+                     << context.error();
     }
 
-    if (offset->package_exists) {
+    if (context->package_exists) {
       container_map[package] = entry.container();
       return entry.container();
     }
@@ -289,18 +245,18 @@
 }
 
 /// Find boolean flag offset in flag value file
-Result<uint32_t> FindBooleanFlagOffset(const std::string& container,
-                                       const std::string& package,
-                                       const std::string& flag) {
+Result<std::pair<FlagValueType, uint32_t>> FindFlagContext(
+    const std::string& container,
+    const std::string& package,
+    const std::string& flag) {
 
-  auto package_map = aconfig_storage::get_mapped_file(
-      container, aconfig_storage::StorageFileType::package_map);
+  auto package_map = get_mapped_file(container, StorageFileType::package_map);
   if (!package_map.ok()) {
     return Error() << "Failed to map package map file for " << container
                    << ": " << package_map.error();
   }
 
-  auto package_context = aconfig_storage::get_package_read_context(*package_map, package);
+  auto package_context = get_package_read_context(*package_map, package);
   if (!package_context.ok()) {
     return Error() << "Failed to get package offset of " << package
                    << " in " << container  << " :" << package_context.error();
@@ -313,14 +269,13 @@
   uint32_t package_id = package_context->package_id;
   uint32_t package_start_index = package_context->boolean_start_index;
 
-  auto flag_map = aconfig_storage::get_mapped_file(
-      container, aconfig_storage::StorageFileType::flag_map);
+  auto flag_map = get_mapped_file(container, StorageFileType::flag_map);
   if (!flag_map.ok()) {
     return Error() << "Failed to map flag map file for " << container
                    << ": " << flag_map.error();
   }
 
-  auto flag_context = aconfig_storage::get_flag_read_context(*flag_map, package_id, flag);
+  auto flag_context = get_flag_read_context(*flag_map, package_id, flag);
   if (!flag_context.ok()) {
     return Error() << "Failed to get flag offset of " << flag
                    << " in " << container  << " :" << flag_context.error();
@@ -330,7 +285,13 @@
     return Error() << flag << " is not found in " << container;
   }
 
-  return package_start_index + flag_context->flag_index;
+  auto value_type = map_to_flag_value_type(flag_context->flag_type);
+  if (!value_type.ok()) {
+    return Error() << "Failed to get flag value type :" << value_type.error();
+  }
+
+  auto index = package_start_index + flag_context->flag_index;
+  return std::make_pair(*value_type, index);
 }
 
 /// Add a new storage
@@ -353,10 +314,10 @@
   return {};
 }
 
-/// Update persistent boolean flag value
-Result<void> UpdateBooleanFlagValue(const std::string& package_name,
-                                    const std::string& flag_name,
-                                    const std::string& flag_value) {
+/// Update persistent flag value
+Result<void> UpdatePersistentFlagValue(const std::string& package_name,
+                                       const std::string& flag_name,
+                                       const std::string& flag_value) {
   auto container_result = FindContainer(package_name);
   if (!container_result.ok()) {
     return Error() << "Failed for find container for package " << package_name
@@ -364,64 +325,114 @@
   }
   auto container = *container_result;
 
-  auto offset_result = FindBooleanFlagOffset(container, package_name, flag_name);
-  if (!offset_result.ok()) {
+  auto context_result = FindFlagContext(container, package_name, flag_name);
+  if (!context_result.ok()) {
     return Error() << "Failed to obtain " << package_name << "."
-                   << flag_name << " flag value offset: " << offset_result.error();
+                   << flag_name << " flag value offset: " << context_result.error();
   }
 
-  auto mapped_file = aconfig_storage::get_mutable_mapped_file(
-      container, aconfig_storage::StorageFileType::flag_val);
-  if (!mapped_file.ok()) {
+  auto mapped_value_file = get_mutable_mapped_file(container, StorageFileType::flag_val);
+  if (!mapped_value_file.ok()) {
     return Error() << "Failed to map flag value file for " << container
-                   << ": " << mapped_file.error();
+                   << ": " << mapped_value_file.error();
   }
 
-  if (flag_value != "true" && flag_value != "false") {
-    return Error() << "Invalid boolean flag value, it should be true|false";
+  auto mapped_info_file = get_mutable_mapped_file(container, StorageFileType::flag_info);
+  if (!mapped_info_file.ok()) {
+    return Error() << "Failed to map flag info file for " << container
+                   << ": " << mapped_info_file.error();
   }
 
-  auto update_result = aconfig_storage::set_boolean_flag_value(
-      *mapped_file, *offset_result, flag_value == "true");
-  if (!update_result.ok()) {
-    return Error() << "Failed to update flag value: " << update_result.error();
+  auto value_type = context_result->first;
+  auto flag_index = context_result->second;
+
+  switch (value_type) {
+    case FlagValueType::Boolean: {
+      if (flag_value != "true" && flag_value != "false") {
+        return Error() << "Invalid boolean flag value, it should be true|false";
+      }
+      auto update_result = set_boolean_flag_value(
+          *mapped_value_file, flag_index, flag_value == "true");
+      if (!update_result.ok()) {
+        return Error() << "Failed to update flag value: " << update_result.error();
+      }
+      update_result = set_flag_has_override(
+          *mapped_info_file, value_type, flag_index, true);
+      if (!update_result.ok()) {
+        return Error() << "Failed to update flag has override: " << update_result.error();
+      }
+      break;
+    }
+    default:
+      return Error() << "Unsupported flag value type";
   }
 
   return {};
 }
 
-/// Query persistent boolean flag value
-Result<bool> GetBooleanFlagValue(const std::string& package_name,
-                                 const std::string& flag_name) {
-  auto container_result = FindContainer(package_name);
-  if (!container_result.ok()) {
+/// Query persistent flag value and info
+Result<std::pair<std::string, uint8_t>> QueryPersistentFlag(
+    const std::string& package_name,
+    const std::string& flag_name) {
+  auto container = FindContainer(package_name);
+  if (!container.ok()) {
     return Error() << "Failed for find container for package " << package_name
-                   << ": " << container_result.error();
+                   << ": " << container.error();
   }
-  auto container = *container_result;
-  auto offset_result = FindBooleanFlagOffset(container, package_name, flag_name);
-  if (!offset_result.ok()) {
+
+  auto context = FindFlagContext(*container, package_name, flag_name);
+  if (!context.ok()) {
     return Error() << "Failed to obtain " << package_name << "."
-                   << flag_name << " flag value offset: " << offset_result.error();
+                   << flag_name << " flag value offset: " << context.error();
+  }
+  auto value_type = context->first;
+  auto flag_index = context->second;
+
+  auto value_file = get_mutable_mapped_file(*container, StorageFileType::flag_val);
+  if (!value_file.ok()) {
+    return Error() << "Failed to map flag value file for " << *container
+                   << ": " << value_file.error();
   }
 
-  auto mapped_file_result = aconfig_storage::get_mutable_mapped_file(
-      container, aconfig_storage::StorageFileType::flag_val);
-  if (!mapped_file_result.ok()) {
-    return Error() << "Failed to map flag value file for " << container
-                   << ": " << mapped_file_result.error();
+  auto info_file = get_mutable_mapped_file(*container, StorageFileType::flag_info);
+  if (!info_file.ok()) {
+    return Error() << "Failed to map flag info file for " << *container
+                   << ": " << info_file.error();
   }
 
-  auto ro_mapped_file = aconfig_storage::MappedStorageFile();
-  ro_mapped_file.file_ptr = mapped_file_result->file_ptr;
-  ro_mapped_file.file_size = mapped_file_result->file_size;
-  auto value_result = aconfig_storage::get_boolean_flag_value(
-      ro_mapped_file, *offset_result);
-  if (!value_result.ok()) {
-    return Error() << "Failed to get flag value: " << value_result.error();
+  // return value
+  auto flag_value = std::string();
+  uint8_t flag_info = 0;
+
+  switch (value_type) {
+    case FlagValueType::Boolean: {
+      // get flag value
+      auto ro_value_file = MappedStorageFile();
+      ro_value_file.file_ptr = value_file->file_ptr;
+      ro_value_file.file_size = value_file->file_size;
+      auto value = get_boolean_flag_value(ro_value_file, flag_index);
+      if (!value.ok()) {
+        return Error() << "Failed to get flag value: " << value.error();
+      }
+      flag_value = *value ? "true" : "false";
+
+      // get flag attribute
+      auto ro_info_file = MappedStorageFile();
+      ro_info_file.file_ptr = info_file->file_ptr;
+      ro_info_file.file_size = info_file->file_size;
+      auto attribute = get_flag_attribute(ro_info_file, value_type, flag_index);
+      if (!attribute.ok()) {
+        return Error() << "Failed to get flag info: " << attribute.error();
+      }
+      flag_info = *attribute;
+
+      break;
+    }
+    default:
+      return Error() << "Unsupported flag value type";
   }
 
-  return *value_result;
+  return std::make_pair(flag_value, flag_info);
 }
 
 } // namespace
@@ -459,15 +470,15 @@
       continue;
     }
 
-    auto updated_result = HandleContainerUpdate(
+    auto updated = HandleContainerUpdate(
         container, package_file, flag_file, value_file);
-    if (!updated_result.ok()) {
-      return Error() << updated_result.error();
+    if (!updated.ok()) {
+      return Error() << updated.error();
     }
 
-    auto copy_result = CreateBootSnapshotForContainer(container);
-    if (!copy_result.ok()) {
-      return Error() << copy_result.error();
+    auto copied = CreateBootSnapshotForContainer(container);
+    if (!copied.ok()) {
+      return Error() << copied.error();
     }
   }
 
@@ -493,12 +504,13 @@
       }
       break;
     }
+
     case StorageRequestMessage::kFlagOverrideMessage: {
       LOG(INFO) << "received a flag override request";
       auto msg = message.flag_override_message();
-      auto result = UpdateBooleanFlagValue(msg.package_name(),
-                                           msg.flag_name(),
-                                           msg.flag_value());
+      auto result = UpdatePersistentFlagValue(msg.package_name(),
+                                              msg.flag_name(),
+                                              msg.flag_value());
       if (!result.ok()) {
         auto* errmsg = return_message.mutable_error_message();
         *errmsg = result.error().message();
@@ -507,17 +519,20 @@
       }
       break;
     }
+
     case StorageRequestMessage::kFlagQueryMessage: {
       LOG(INFO) << "received a flag query request";
       auto msg = message.flag_query_message();
-      auto result = GetBooleanFlagValue(msg.package_name(),
-                                        msg.flag_name());
+      auto result = QueryPersistentFlag(msg.package_name(), msg.flag_name());
       if (!result.ok()) {
         auto* errmsg = return_message.mutable_error_message();
         *errmsg = result.error().message();
       } else {
         auto return_msg = return_message.mutable_flag_query_message();
-        return_msg->set_flag_value(*result ? "true" : "false");
+        return_msg->set_flag_value(result->first);
+        return_msg->set_is_sticky(result->second & FlagInfoBit::IsSticky);
+        return_msg->set_is_readwrite(result->second & FlagInfoBit::IsReadWrite);
+        return_msg->set_has_override(result->second & FlagInfoBit::HasOverride);
       }
       break;
     }
diff --git a/aconfigd/aconfigd.h b/aconfigd/aconfigd.h
index 2a9b4f1..3020e28 100644
--- a/aconfigd/aconfigd.h
+++ b/aconfigd/aconfigd.h
@@ -29,6 +29,14 @@
     /// Socket message buffer size
     static constexpr size_t kBufferSize = 4096;
 
+    /// Persistent storage records pb file full path
+    static constexpr char kPersistentStorageRecordsFileName[] =
+        "/metadata/aconfig/persistent_storage_file_records.pb";
+
+    /// Persistent storage records pb file full path
+    static constexpr char kAvailableStorageRecordsFileName[] =
+        "/metadata/aconfig/boot/available_storage_file_records.pb";
+
     /// Initialize platform RO partition flag storages
     base::Result<void> InitializePlatformStorage();
 
diff --git a/aconfigd/aconfigd.proto b/aconfigd/aconfigd.proto
index 6c05951..eb1d788 100644
--- a/aconfigd/aconfigd.proto
+++ b/aconfigd/aconfigd.proto
@@ -34,7 +34,7 @@
     optional string flag_value = 3;
   }
 
-  // query persistent flag value
+  // query persistent flag value and info
   message FlagQueryMessage {
     optional string package_name = 1;
     optional string flag_name = 2;
@@ -59,6 +59,9 @@
 
   message FlagQueryReturnMessage {
     optional string flag_value = 1;
+    optional bool is_sticky = 2;
+    optional bool is_readwrite = 3;
+    optional bool has_override = 4;
   }
 
   oneof msg {
diff --git a/aconfigd/aconfigd_main.cpp b/aconfigd/aconfigd_main.cpp
index e9109cc..24c1830 100644
--- a/aconfigd/aconfigd_main.cpp
+++ b/aconfigd/aconfigd_main.cpp
@@ -137,7 +137,7 @@
 
 int main(int argc, char** argv) {
   if (!com::android::aconfig_new_storage::enable_aconfig_storage_daemon()) {
-    return 0;
+    // return 0;
   }
 
   android::base::InitLogging(argv, &android::base::KernelLogger);
diff --git a/aconfigd/aconfigd_test.cpp b/aconfigd/aconfigd_test.cpp
index d2d38e4..4ee6754 100644
--- a/aconfigd/aconfigd_test.cpp
+++ b/aconfigd/aconfigd_test.cpp
@@ -173,6 +173,9 @@
   ASSERT_TRUE(return_message.has_flag_query_message());
   auto query = return_message.flag_query_message();
   ASSERT_EQ(query.flag_value(), "true");
+  ASSERT_EQ(query.is_sticky(), false);
+  ASSERT_EQ(query.is_readwrite(), true);
+  ASSERT_EQ(query.has_override(), true);
 
   flag_override_result = send_flag_override_message(
       "com.android.aconfig.storage.test_1", "enabled_rw", "false");
@@ -189,9 +192,12 @@
   ASSERT_TRUE(return_message.has_flag_query_message());
   query = return_message.flag_query_message();
   ASSERT_EQ(query.flag_value(), "false");
+  ASSERT_EQ(query.is_sticky(), false);
+  ASSERT_EQ(query.is_readwrite(), true);
+  ASSERT_EQ(query.has_override(), true);
 }
 
-TEST(aconfigd_socket, invalid_flag_override_message) {
+TEST(aconfigd_socket, nonexist_flag_override_message) {
   auto new_storage_result = send_new_storage_message();
   ASSERT_TRUE(new_storage_result.ok()) << new_storage_result.error();
   ASSERT_EQ(new_storage_result->msgs_size(), 1);
@@ -208,7 +214,7 @@
   ASSERT_TRUE(errmsg.find("unknown is not found in mockup") != std::string::npos);
 }
 
-TEST(aconfigd_socket, invalid_flag_query_message) {
+TEST(aconfigd_socket, nonexist_flag_query_message) {
   auto new_storage_result = send_new_storage_message();
   ASSERT_TRUE(new_storage_result.ok()) << new_storage_result.error();
   ASSERT_EQ(new_storage_result->msgs_size(), 1);
diff --git a/aconfigd/aconfigd_util.cpp b/aconfigd/aconfigd_util.cpp
index bbd1932..72a0b10 100644
--- a/aconfigd/aconfigd_util.cpp
+++ b/aconfigd/aconfigd_util.cpp
@@ -25,9 +25,7 @@
 
 #include "aconfigd_util.h"
 
-using ::android::base::Result;
-using ::android::base::Error;
-using ::android::base::ErrnoError;
+using namespace android::base;
 
 namespace android {
 namespace aconfigd {
@@ -106,5 +104,42 @@
   return stat(file.c_str(), &st) == 0 ? true : false;
 }
 
+/// Read persistent aconfig storage records pb file
+Result<aconfig_storage_metadata::storage_files> ReadStorageRecordsPb(
+    const std::string& pb_file) {
+  auto records = aconfig_storage_metadata::storage_files();
+  if (FileExists(pb_file)) {
+    auto content = std::string();
+    if (!ReadFileToString(pb_file, &content)) {
+      return ErrnoError() << "ReadFileToString failed";
+    }
+
+    if (!records.ParseFromString(content)) {
+      return ErrnoError() << "Unable to parse storage records protobuf";
+    }
+  }
+  return records;
+}
+
+/// Write aconfig storage records protobuf to file
+Result<void> WriteStorageRecordsPbToFile(
+    const aconfig_storage_metadata::storage_files& records_pb,
+    const std::string& file_name) {
+  auto content = std::string();
+  if (!records_pb.SerializeToString(&content)) {
+    return ErrnoError() << "Unable to serialize storage records protobuf";
+  }
+
+  if (!WriteStringToFile(content, file_name)) {
+    return ErrnoError() << "WriteStringToFile failed";
+  }
+
+  if (chmod(file_name.c_str(), 0644) == -1) {
+    return ErrnoError() << "chmod() failed";
+  };
+
+  return {};
+}
+
 } // namespace aconfig
 } // namespace android
diff --git a/aconfigd/aconfigd_util.h b/aconfigd/aconfigd_util.h
index 482e25c..e25fd8a 100644
--- a/aconfigd/aconfigd_util.h
+++ b/aconfigd/aconfigd_util.h
@@ -17,6 +17,7 @@
 #include <string>
 #include <android-base/result.h>
 #include <sys/stat.h>
+#include <protos/aconfig_storage_metadata.pb.h>
 
 namespace android {
   namespace aconfigd {
@@ -33,5 +34,14 @@
   /// Check if file exists
   bool FileExists(const std::string& file);
 
+  /// Read persistent aconfig storage records pb file
+  base::Result<aconfig_storage_metadata::storage_files> ReadStorageRecordsPb(
+      const std::string& pb_file);
+
+  /// Write aconfig storage records protobuf to file
+  base::Result<void> WriteStorageRecordsPbToFile(
+      const aconfig_storage_metadata::storage_files& records_pb,
+      const std::string& file_name);
+
   }// namespace aconfig
 } // namespace android