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