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