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 <dlfcn.h>
18 #include <stdint.h>
19 #include <string.h>
20
21 #include <string>
22 #include <string_view>
23 #include <vector>
24
25 #include <android-base/endian.h>
26 #include <android-base/logging.h>
27 #include <android-base/strings.h>
28 #include <app_nugget.h>
29 #include <misc_writer/misc_writer.h>
30 #include <nos/NuggetClient.h>
31 #include <nos/debug.h>
32 #include <recovery_ui/device.h>
33 #include <recovery_ui/screen_ui.h>
34
35 namespace android {
36 namespace hardware {
37 namespace google {
38 namespace pixel {
39
40 namespace {
41
42 /** Wipe user data from Titan M. */
WipeTitanM()43 bool WipeTitanM() {
44 // Connect to Titan M
45 ::nos::NuggetClient client;
46 client.Open();
47 if (!client.IsOpen()) {
48 LOG(ERROR) << "Failed to connect to Titan M";
49 return false;
50 }
51
52 // Tell it to wipe user data
53 const uint32_t magicValue = htole32(ERASE_CONFIRMATION);
54 std::vector<uint8_t> magic(sizeof(magicValue));
55 memcpy(magic.data(), &magicValue, sizeof(magicValue));
56 const uint32_t status
57 = client.CallApp(APP_ID_NUGGET, NUGGET_PARAM_NUKE_FROM_ORBIT, magic, nullptr);
58 if (status != APP_SUCCESS) {
59 LOG(ERROR) << "Titan M user data wipe failed: " << ::nos::StatusCodeString(status)
60 << " (" << status << ")";
61 return false;
62 }
63
64 LOG(INFO) << "Titan M wipe successful";
65 return true;
66 }
67
68 /** Call device-specifc WipeKeys function, if any. */
WipeKeysHook(::RecoveryUI * const ui)69 bool WipeKeysHook(::RecoveryUI *const ui) {
70 bool *(*WipeKeysFunc)(::RecoveryUI *const);
71 reinterpret_cast<void *&>(WipeKeysFunc) = dlsym(RTLD_DEFAULT, "WipeKeys");
72 if (WipeKeysFunc == nullptr) {
73 LOG(INFO) << "No WipeKeys implementation";
74 return true;
75 }
76
77 return (*WipeKeysFunc)(ui);
78 }
79
80 // Wipes the provisioned flag as part of data wipe.
WipeProvisionedFlag()81 bool WipeProvisionedFlag() {
82 // Must be consistent with the one in init.hardware.rc (10-byte `theme-dark`).
83 MiscWriter misc_writer(MiscWriterActions::kClearDarkThemeFlag);
84 if (!misc_writer.PerformAction()) {
85 LOG(ERROR) << "Failed to clear the dark theme flag";
86 return false;
87 }
88 LOG(INFO) << "Provisioned flag wiped successful";
89 return true;
90 }
91
92 // Wipes user preferred resolution as part of data wipe
WipeUserPreferredResolution()93 bool WipeUserPreferredResolution() {
94 MiscWriter misc_writer(MiscWriterActions::kClearDisplayMode);
95 if (!misc_writer.PerformAction()) {
96 LOG(ERROR) << "Failed to clear the user preferred resolution";
97 return false;
98 }
99 LOG(INFO) << "User preferred resolution wiped successful";
100 return true;
101 }
102
103 // Provision Silent OTA(SOTA) flag while reason is "enable-sota"
ProvisionSilentOtaFlag(const std::string & reason)104 bool ProvisionSilentOtaFlag(const std::string& reason) {
105 if (android::base::StartsWith(reason, MiscWriter::kSotaFlag)) {
106 MiscWriter misc_writer(MiscWriterActions::kSetSotaFlag);
107 if (!misc_writer.PerformAction()) {
108 LOG(ERROR) << "Failed to set the silent ota flag";
109 return false;
110 }
111 LOG(INFO) << "Silent ota flag set successful";
112 }
113 return true;
114 }
115
116 } // namespace
117
118 class PixelDevice : public ::Device {
119 public:
PixelDevice(::ScreenRecoveryUI * const ui)120 explicit PixelDevice(::ScreenRecoveryUI* const ui) : ::Device(ui) {}
121
122 /** Hook to wipe user data not stored in /data */
PostWipeData()123 bool PostWipeData() override {
124 // Try to do everything but report a failure if anything wasn't successful
125 bool totalSuccess = false;
126 ::RecoveryUI* const ui = GetUI();
127
128 ui->Print("Wiping Titan M...\n");
129
130 uint32_t retries = 5;
131 while (retries--) {
132 if (WipeTitanM()) {
133 totalSuccess = true;
134 break;
135 }
136 }
137
138 if (!WipeKeysHook(ui)) {
139 totalSuccess = false;
140 }
141
142 if (!WipeProvisionedFlag()) {
143 totalSuccess = false;
144 }
145
146 if (!WipeUserPreferredResolution()) {
147 totalSuccess = false;
148 }
149
150 // Extendable to wipe other components
151
152 // Additional behavior along with wiping data
153 auto reason = GetReason();
154 CHECK(reason.has_value());
155 if (!ProvisionSilentOtaFlag(reason.value())) {
156 totalSuccess = false;
157 }
158
159 return totalSuccess;
160 }
161 };
162
163 } // namespace pixel
164 } // namespace google
165 } // namespace hardware
166 } // namespace android
167
make_device()168 Device *make_device() {
169 return new ::android::hardware::google::pixel::PixelDevice(new ::ScreenRecoveryUI);
170 }
171