1 //
2 // Copyright (C) 2020 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 #include "misc_info.h"
17
18 #include <algorithm>
19
20 #include <android-base/logging.h>
21 #include <android-base/stringprintf.h>
22 #include <android-base/strings.h>
23
24 namespace cuttlefish {
25
ParseMiscInfo(const std::string & misc_info_contents)26 MiscInfo ParseMiscInfo(const std::string& misc_info_contents) {
27 auto lines = android::base::Split(misc_info_contents, "\n");
28 MiscInfo misc_info;
29 for (auto& line : lines) {
30 line = android::base::Trim(line);
31 if (line.size() == 0) {
32 continue;
33 }
34 auto eq_pos = line.find('=');
35 if (eq_pos == std::string::npos) {
36 LOG(WARNING) << "Line in unknown format: \"" << line << "\"";
37 continue;
38 }
39 // Not using android::base::Split here to only capture the first =
40 auto key = android::base::Trim(line.substr(0, eq_pos));
41 auto value = android::base::Trim(line.substr(eq_pos + 1));
42 if (misc_info.find(key) != misc_info.end() && misc_info[key] != value) {
43 LOG(ERROR) << "Duplicate key: \"" << key << "\". First value: \""
44 << misc_info[key] << "\", Second value: \"" << value << "\"";
45 return {};
46 }
47 misc_info[key] = value;
48 }
49 return misc_info;
50 }
51
WriteMiscInfo(const MiscInfo & misc_info)52 std::string WriteMiscInfo(const MiscInfo& misc_info) {
53 std::stringstream out;
54 for (const auto& entry : misc_info) {
55 out << entry.first << "=" << entry.second << "\n";
56 }
57 return out.str();
58 }
59
60 static const std::string kDynamicPartitions = "dynamic_partition_list";
61
SuperPartitionComponents(const MiscInfo & info)62 std::vector<std::string> SuperPartitionComponents(const MiscInfo& info) {
63 auto value_it = info.find(kDynamicPartitions);
64 if (value_it == info.end()) {
65 return {};
66 }
67 auto components = android::base::Split(value_it->second, " ");
68 for (auto& component : components) {
69 component = android::base::Trim(component);
70 }
71 components.erase(std::remove(components.begin(), components.end(), ""),
72 components.end());
73 return components;
74 }
75
76 static constexpr const char* kGoogleDynamicPartitions =
77 "google_dynamic_partitions";
78 static constexpr const char* kSuperPartitionGroups = "super_partition_groups";
79
SetSuperPartitionComponents(const std::vector<std::string> & components,MiscInfo * misc_info)80 bool SetSuperPartitionComponents(const std::vector<std::string>& components,
81 MiscInfo* misc_info) {
82 auto super_partition_groups = misc_info->find(kSuperPartitionGroups);
83 if (super_partition_groups == misc_info->end()) {
84 LOG(ERROR) << "Failed to find super partition groups in misc_info";
85 return false;
86 }
87
88 // Remove all existing update groups in misc_info
89 auto update_groups =
90 android::base::Split(super_partition_groups->second, " ");
91 for (const auto& group_name : update_groups) {
92 auto partition_list = android::base::StringPrintf("super_%s_partition_list",
93 group_name.c_str());
94 auto partition_size =
95 android::base::StringPrintf("super_%s_group_size", group_name.c_str());
96 for (const auto& key : {partition_list, partition_size}) {
97 auto it = misc_info->find(key);
98 if (it == misc_info->end()) {
99 LOG(ERROR) << "Failed to find " << key << " in misc_info";
100 return false;
101 }
102 misc_info->erase(it);
103 }
104 }
105
106 // For merged target-file, put all dynamic partitions under the
107 // google_dynamic_partitions update group.
108 // TODO(xunchang) use different update groups for system and vendor images.
109 (*misc_info)[kDynamicPartitions] = android::base::Join(components, " ");
110 (*misc_info)[kSuperPartitionGroups] = kGoogleDynamicPartitions;
111 std::string partitions_list_key = android::base::StringPrintf(
112 "super_%s_partition_list", kGoogleDynamicPartitions);
113 (*misc_info)[partitions_list_key] = android::base::Join(components, " ");
114
115 // Use the entire super partition as the group size
116 std::string group_size_key = android::base::StringPrintf(
117 "super_%s_group_size", kGoogleDynamicPartitions);
118 auto super_size_it = misc_info->find("super_partition_size");
119 if (super_size_it == misc_info->end()) {
120 LOG(ERROR) << "Failed to find super partition size";
121 return false;
122 }
123 (*misc_info)[group_size_key] = super_size_it->second;
124 return true;
125 }
126
127 } // namespace cuttlefish
128