1 /*
2 * Copyright (C) 2019 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 #include "misc_writer/misc_writer.h"
18
19 #include <android-base/file.h>
20 #include <android-base/logging.h>
21 #include <android-base/properties.h>
22 #include <android-base/stringprintf.h>
23 #include <bootloader_message/bootloader_message.h>
24 #include <string.h>
25 #include <charconv>
26
27 namespace android {
28 namespace hardware {
29 namespace google {
30 namespace pixel {
31
OffsetAndSizeInVendorSpace(size_t offset,size_t size)32 bool MiscWriter::OffsetAndSizeInVendorSpace(size_t offset, size_t size) {
33 auto total_size = WIPE_PACKAGE_OFFSET_IN_MISC - VENDOR_SPACE_OFFSET_IN_MISC;
34 return size <= total_size && offset <= total_size - size;
35 }
36
WriteMiscPartitionVendorSpace(const void * data,size_t size,size_t offset,std::string * err)37 bool MiscWriter::WriteMiscPartitionVendorSpace(const void* data, size_t size, size_t offset,
38 std::string* err) {
39 if (!OffsetAndSizeInVendorSpace(offset, size)) {
40 *err = android::base::StringPrintf("Out of bound write (offset %zu size %zu)", offset, size);
41 return false;
42 }
43 auto misc_blk_device = get_misc_blk_device(err);
44 if (misc_blk_device.empty()) {
45 return false;
46 }
47 return write_misc_partition(data, size, misc_blk_device, VENDOR_SPACE_OFFSET_IN_MISC + offset,
48 err);
49 }
50
PerformAction(std::optional<size_t> override_offset)51 bool MiscWriter::PerformAction(std::optional<size_t> override_offset) {
52 size_t offset = 0;
53 std::string content;
54 switch (action_) {
55 case MiscWriterActions::kSetDarkThemeFlag:
56 case MiscWriterActions::kClearDarkThemeFlag:
57 offset = override_offset.value_or(kThemeFlagOffsetInVendorSpace);
58 content = (action_ == MiscWriterActions::kSetDarkThemeFlag)
59 ? kDarkThemeFlag
60 : std::string(strlen(kDarkThemeFlag), 0);
61 break;
62 case MiscWriterActions::kSetSotaFlag:
63 case MiscWriterActions::kClearSotaFlag:
64 offset = override_offset.value_or(kSotaFlagOffsetInVendorSpace);
65 content = (action_ == MiscWriterActions::kSetSotaFlag) ? kSotaFlag
66 : std::string(strlen(kSotaFlag), 0);
67 break;
68 case MiscWriterActions::kSetEnablePkvmFlag:
69 case MiscWriterActions::kSetDisablePkvmFlag:
70 offset = override_offset.value_or(kPkvmFlagOffsetInVendorSpace);
71 content = (action_ == MiscWriterActions::kSetEnablePkvmFlag) ? kEnablePkvmFlag
72 : kDisablePkvmFlag;
73 break;
74 case MiscWriterActions::kSetWristOrientationFlag:
75 case MiscWriterActions::kClearWristOrientationFlag:
76 offset = override_offset.value_or(kWristOrientationFlagOffsetInVendorSpace);
77 content = (action_ == MiscWriterActions::kSetWristOrientationFlag)
78 ? std::string(kWristOrientationFlag) + chardata_
79 : std::string(strlen(kWristOrientationFlag) + sizeof(chardata_), 0);
80 break;
81 case MiscWriterActions::kWriteTimeFormat:
82 offset = override_offset.value_or(kTimeFormatValOffsetInVendorSpace);
83 content = std::string(kTimeFormat) + chardata_;
84 break;
85 case MiscWriterActions::kWriteTimeOffset:
86 offset = override_offset.value_or(kTimeOffsetValOffsetInVendorSpace);
87 content = std::string(kTimeOffset) + stringdata_;
88 content.resize(strlen(kTimeOffset) + std::to_string(kMinTimeOffset).size(), 0);
89 break;
90 case MiscWriterActions::kSetMaxRamSize:
91 case MiscWriterActions::kClearMaxRamSize:
92 offset = override_offset.value_or(kMaxRamSizeOffsetInVendorSpace);
93 content = (action_ == MiscWriterActions::kSetMaxRamSize)
94 ? std::string(kMaxRamSize).append(stringdata_).append("\n")
95 : std::string(32, 0);
96 break;
97 case MiscWriterActions::kWriteTimeRtcOffset:
98 offset = override_offset.value_or(kRTimeRtcOffsetValOffsetInVendorSpace);
99 content = std::string(kTimeRtcOffset) + stringdata_;
100 content.resize(32);
101 break;
102 case MiscWriterActions::kWriteTimeMinRtc:
103 offset = override_offset.value_or(kRTimeMinRtcValOffsetInVendorSpace);
104 content = std::string(kTimeMinRtc) + stringdata_;
105 content.resize(32);
106 break;
107 case MiscWriterActions::kSetSotaConfig:
108 return UpdateSotaConfig(override_offset);
109 case MiscWriterActions::kWriteDstTransition:
110 offset = override_offset.value_or(kDstTransitionOffsetInVendorSpace);
111 content = std::string(kDstTransition) + stringdata_;
112 content.resize(32);
113 break;
114 case MiscWriterActions::kWriteDstOffset:
115 offset = override_offset.value_or(kDstOffsetOffsetInVendorSpace);
116 content = std::string(kDstOffset) + stringdata_;
117 content.resize(32);
118 break;
119 case MiscWriterActions::kSetDisplayMode:
120 case MiscWriterActions::kClearDisplayMode:
121 offset = override_offset.value_or(kDisplayModeOffsetInVendorSpace);
122 content = (action_ == MiscWriterActions::kSetDisplayMode)
123 ? std::string(kDisplayModePrefix) + stringdata_
124 : std::string(32, 0);
125 content.resize(32, 0);
126 break;
127 case MiscWriterActions::kWriteEagleEyePatterns:
128 offset = override_offset.value_or(kEagleEyeOffset);
129 content = stringdata_;
130 content.resize(sizeof(bootloader_message_vendor_t::eagleEye), 0);
131 break;
132 case MiscWriterActions::kSetDisableFaceauthEval:
133 case MiscWriterActions::kClearDisableFaceauthEval:
134 offset = override_offset.value_or(kFaceauthEvalValOffsetInVendorSpace);
135 content = (action_ == MiscWriterActions::kSetDisableFaceauthEval)
136 ? kDisableFaceauthEvalFlag
137 : std::string(32, 0);
138 content.resize(32, 0);
139 break;
140 case MiscWriterActions::kUnset:
141 LOG(ERROR) << "The misc writer action must be set";
142 return false;
143 }
144
145 if (std::string err;
146 !WriteMiscPartitionVendorSpace(content.data(), content.size(), offset, &err)) {
147 LOG(ERROR) << "Failed to write " << content << " at offset " << offset << " : " << err;
148 return false;
149 }
150 return true;
151 }
152
UpdateSotaConfig(std::optional<size_t> override_offset)153 bool MiscWriter::UpdateSotaConfig(std::optional<size_t> override_offset) {
154 size_t offset = 0;
155 std::string content;
156 std::string err;
157
158 // Update sota state
159 offset = override_offset.value_or(kSotaStateOffsetInVendorSpace);
160 content = ::android::base::GetProperty("persist.vendor.nfc.factoryota.state", "");
161 if (content.size() != 0) {
162 content.resize(sizeof(bootloader_message_vendor_t::sota_client_state));
163 if (!WriteMiscPartitionVendorSpace(content.data(), content.size(), offset, &err)) {
164 LOG(ERROR) << "Failed to write " << content << " at offset " << offset << " : " << err;
165 return false;
166 }
167 }
168
169 // Update sota schedule_shipmode
170 offset = override_offset.value_or(kSotaScheduleShipmodeOffsetInVendorSpace);
171 content = ::android::base::GetProperty("persist.vendor.nfc.factoryota.schedule_shipmode", "");
172 if (content.size() != 0) {
173 content.resize(sizeof(bootloader_message_vendor_t::sota_schedule_shipmode));
174 if (!WriteMiscPartitionVendorSpace(content.data(), content.size(), offset, &err)) {
175 LOG(ERROR) << "Failed to write " << content << " at offset " << offset << " : " << err;
176 return false;
177 }
178 }
179
180 // Update sota csku signature
181 offset = override_offset.value_or(offsetof(bootloader_message_vendor_t, sota_csku_signature));
182 std::string signature;
183 signature += ::android::base::GetProperty("persist.vendor.factoryota.signature1", "");
184 signature += ::android::base::GetProperty("persist.vendor.factoryota.signature2", "");
185 signature += ::android::base::GetProperty("persist.vendor.factoryota.signature3", "");
186 if (signature.size() != 0) {
187 LOG(INFO) << "persist.vendor.factoryota.signature=" << signature;
188 if (signature.length() != 2 * sizeof(bootloader_message_vendor_t::sota_csku_signature)) {
189 LOG(ERROR) << "signature.length() should be "
190 << 2 * sizeof(bootloader_message_vendor_t::sota_csku_signature) << " not "
191 << signature.length();
192 return false;
193 }
194 content.resize(sizeof(bootloader_message_vendor_t::sota_csku_signature));
195 // Traslate hex string to bytes
196 for (size_t i = 0; i < 2 * content.size(); i += 2)
197 if (std::from_chars(&signature[i], &signature[i + 2], content[i / 2], 16).ec != std::errc{}) {
198 LOG(ERROR) << "Failed to convert " << signature << " to bytes";
199 return false;
200 }
201 if (!WriteMiscPartitionVendorSpace(content.data(), content.size(), offset, &err)) {
202 LOG(ERROR) << "Failed to write signature at offset " << offset << " : " << err;
203 return false;
204 }
205
206 // Update sota csku
207 offset = override_offset.value_or(offsetof(bootloader_message_vendor_t, sota_csku));
208 content = ::android::base::GetProperty("persist.vendor.factoryota.csku", "");
209 content.resize(sizeof(bootloader_message_vendor_t::sota_csku));
210 LOG(INFO) << "persist.vendor.factoryota.csku=" << content;
211 if (!WriteMiscPartitionVendorSpace(content.data(), content.size(), offset, &err)) {
212 LOG(ERROR) << "Failed to write " << content << " at offset " << offset << " : " << err;
213 return false;
214 }
215 }
216
217 return true;
218 }
219
220 } // namespace pixel
221 } // namespace google
222 } // namespace hardware
223 } // namespace android
224