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 
26 namespace android {
27 namespace hardware {
28 namespace google {
29 namespace pixel {
30 
OffsetAndSizeInVendorSpace(size_t offset,size_t size)31 bool MiscWriter::OffsetAndSizeInVendorSpace(size_t offset, size_t size) {
32   auto total_size = WIPE_PACKAGE_OFFSET_IN_MISC - VENDOR_SPACE_OFFSET_IN_MISC;
33   return size <= total_size && offset <= total_size - size;
34 }
35 
WriteMiscPartitionVendorSpace(const void * data,size_t size,size_t offset,std::string * err)36 bool MiscWriter::WriteMiscPartitionVendorSpace(const void* data, size_t size, size_t offset,
37                                                std::string* err) {
38   if (!OffsetAndSizeInVendorSpace(offset, size)) {
39     *err = android::base::StringPrintf("Out of bound write (offset %zu size %zu)", offset, size);
40     return false;
41   }
42   auto misc_blk_device = get_misc_blk_device(err);
43   if (misc_blk_device.empty()) {
44     return false;
45   }
46   return write_misc_partition(data, size, misc_blk_device, VENDOR_SPACE_OFFSET_IN_MISC + offset,
47                               err);
48 }
49 
PerformAction(std::optional<size_t> override_offset)50 bool MiscWriter::PerformAction(std::optional<size_t> override_offset) {
51   size_t offset = 0;
52   std::string content;
53   switch (action_) {
54     case MiscWriterActions::kSetDarkThemeFlag:
55     case MiscWriterActions::kClearDarkThemeFlag:
56       offset = override_offset.value_or(kThemeFlagOffsetInVendorSpace);
57       content = (action_ == MiscWriterActions::kSetDarkThemeFlag)
58                     ? kDarkThemeFlag
59                     : std::string(strlen(kDarkThemeFlag), 0);
60       break;
61     case MiscWriterActions::kSetSotaFlag:
62     case MiscWriterActions::kClearSotaFlag:
63       offset = override_offset.value_or(kSotaFlagOffsetInVendorSpace);
64       content = (action_ == MiscWriterActions::kSetSotaFlag) ? kSotaFlag
65                                                              : std::string(strlen(kSotaFlag), 0);
66       break;
67     case MiscWriterActions::kSetEnablePkvmFlag:
68     case MiscWriterActions::kSetDisablePkvmFlag:
69       offset = override_offset.value_or(kPkvmFlagOffsetInVendorSpace);
70       content = (action_ == MiscWriterActions::kSetEnablePkvmFlag) ? kEnablePkvmFlag
71                                                                    : kDisablePkvmFlag;
72       break;
73     case MiscWriterActions::kSetWristOrientationFlag:
74     case MiscWriterActions::kClearWristOrientationFlag:
75       offset = override_offset.value_or(kWristOrientationFlagOffsetInVendorSpace);
76       content = (action_ == MiscWriterActions::kSetWristOrientationFlag)
77                     ? std::string(kWristOrientationFlag) + chardata_
78                     : std::string(strlen(kWristOrientationFlag) + sizeof(chardata_), 0);
79       break;
80     case MiscWriterActions::kWriteTimeFormat:
81         offset = override_offset.value_or(kTimeFormatValOffsetInVendorSpace);
82         content = std::string(kTimeFormat) + chardata_;
83         break;
84     case MiscWriterActions::kWriteTimeOffset:
85         offset = override_offset.value_or(kTimeOffsetValOffsetInVendorSpace);
86         content = std::string(kTimeOffset) + stringdata_;
87         content.resize(strlen(kTimeOffset) + std::to_string(kMinTimeOffset).size(), 0);
88         break;
89     case MiscWriterActions::kSetMaxRamSize:
90     case MiscWriterActions::kClearMaxRamSize:
91         offset = override_offset.value_or(kMaxRamSizeOffsetInVendorSpace);
92         content = (action_ == MiscWriterActions::kSetMaxRamSize)
93                           ? std::string(kMaxRamSize).append(stringdata_).append("\n")
94                           : std::string(32, 0);
95         break;
96     case MiscWriterActions::kWriteTimeRtcOffset:
97         offset = override_offset.value_or(kRTimeRtcOffsetValOffsetInVendorSpace);
98         content = std::string(kTimeRtcOffset) + stringdata_;
99         content.resize(32);
100         break;
101     case MiscWriterActions::kWriteTimeMinRtc:
102         offset = override_offset.value_or(kRTimeMinRtcValOffsetInVendorSpace);
103         content = std::string(kTimeMinRtc) + stringdata_;
104         content.resize(32);
105         break;
106     case MiscWriterActions::kSetSotaConfig:
107         goto sota_config;
108     case MiscWriterActions::kWriteDstTransition:
109         offset = override_offset.value_or(kDstTransitionOffsetInVendorSpace);
110         content = std::string(kDstTransition) + stringdata_;
111         content.resize(32);
112         break;
113     case MiscWriterActions::kWriteDstOffset:
114         offset = override_offset.value_or(kDstOffsetOffsetInVendorSpace);
115         content = std::string(kDstOffset) + stringdata_;
116         content.resize(32);
117         break;
118     case MiscWriterActions::kSetDisplayMode:
119     case MiscWriterActions::kClearDisplayMode:
120         offset = override_offset.value_or(kDisplayModeOffsetInVendorSpace);
121         content = (action_ == MiscWriterActions::kSetDisplayMode)
122                           ? std::string(kDisplayModePrefix) + stringdata_
123                           : std::string(32, 0);
124         content.resize(32, 0);
125         break;
126     case MiscWriterActions::kUnset:
127       LOG(ERROR) << "The misc writer action must be set";
128       return false;
129   }
130 
131   if (std::string err;
132       !WriteMiscPartitionVendorSpace(content.data(), content.size(), offset, &err)) {
133     LOG(ERROR) << "Failed to write " << content << " at offset " << offset << " : " << err;
134     return false;
135   }
136 
137 sota_config:
138   if (action_ == MiscWriterActions::kSetSotaFlag || action_ == MiscWriterActions::kSetSotaConfig) {
139     content = ::android::base::GetProperty("persist.vendor.nfc.factoryota.state", "");
140     if (content.size() != 0 && content.size() <= 40) {
141       offset = kSotaStateOffsetInVendorSpace;
142       if (std::string err;
143           !WriteMiscPartitionVendorSpace(content.data(), content.size(), offset, &err)) {
144           LOG(ERROR) << "Failed to write " << content << " at offset " << offset << " : " << err;
145           return false;
146       }
147     }
148     content = ::android::base::GetProperty("persist.vendor.nfc.factoryota.schedule_shipmode", "");
149     if (content.size() != 0 && content.size() <= 32) {
150       offset = kSotaScheduleShipmodeOffsetInVendorSpace;
151       if (std::string err;
152           !WriteMiscPartitionVendorSpace(content.data(), content.size(), offset, &err)) {
153           LOG(ERROR) << "Failed to write " << content << " at offset " << offset << " : " << err;
154           return false;
155       }
156     }
157   }
158 
159   return true;
160 }
161 
162 }  // namespace pixel
163 }  // namespace google
164 }  // namespace hardware
165 }  // namespace android
166