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