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 // Provision Silent OTA(SOTA) flag while reason is "enable-sota"
ProvisionSilentOtaFlag(const std::string & reason)93 bool ProvisionSilentOtaFlag(const std::string& reason) {
94 if (android::base::StartsWith(reason, MiscWriter::kSotaFlag)) {
95 MiscWriter misc_writer(MiscWriterActions::kSetSotaFlag);
96 if (!misc_writer.PerformAction()) {
97 LOG(ERROR) << "Failed to set the silent ota flag";
98 return false;
99 }
100 LOG(INFO) << "Silent ota flag set successful";
101 }
102 return true;
103 }
104
105 } // namespace
106
107 class PixelDevice : public ::Device {
108 public:
PixelDevice(::ScreenRecoveryUI * const ui)109 explicit PixelDevice(::ScreenRecoveryUI* const ui) : ::Device(ui) {}
110
111 /** Hook to wipe user data not stored in /data */
PostWipeData()112 bool PostWipeData() override {
113 // Try to do everything but report a failure if anything wasn't successful
114 bool totalSuccess = false;
115 ::RecoveryUI* const ui = GetUI();
116
117 ui->Print("Wiping Titan M...\n");
118
119 uint32_t retries = 5;
120 while (retries--) {
121 if (WipeTitanM()) {
122 totalSuccess = true;
123 break;
124 }
125 }
126
127 if (!WipeKeysHook(ui)) {
128 totalSuccess = false;
129 }
130
131 if (!WipeProvisionedFlag()) {
132 totalSuccess = false;
133 }
134
135 // Extendable to wipe other components
136
137 // Additional behavior along with wiping data
138 auto reason = GetReason();
139 CHECK(reason.has_value());
140 if (!ProvisionSilentOtaFlag(reason.value())) {
141 totalSuccess = false;
142 }
143
144 return totalSuccess;
145 }
146 };
147
148 } // namespace pixel
149 } // namespace google
150 } // namespace hardware
151 } // namespace android
152
make_device()153 Device *make_device() {
154 return new ::android::hardware::google::pixel::PixelDevice(new ::ScreenRecoveryUI);
155 }
156