• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //
2 // Copyright (C) 2016 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 <xz.h>
18 
19 #include <string>
20 #include <vector>
21 
22 #include <base/command_line.h>
23 #include <base/strings/string_split.h>
24 #include <base/strings/stringprintf.h>
25 #include <brillo/asynchronous_signal_handler.h>
26 #include <brillo/flag_helper.h>
27 #include <brillo/message_loops/base_message_loop.h>
28 #include <brillo/streams/file_stream.h>
29 #include <brillo/streams/stream.h>
30 
31 #include "update_engine/common/boot_control.h"
32 #include "update_engine/common/error_code_utils.h"
33 #include "update_engine/common/hardware.h"
34 #include "update_engine/common/prefs.h"
35 #include "update_engine/common/subprocess.h"
36 #include "update_engine/common/terminator.h"
37 #include "update_engine/common/utils.h"
38 #include "update_engine/logging.h"
39 #include "update_engine/update_attempter_android.h"
40 
41 using std::string;
42 using std::vector;
43 using update_engine::UpdateEngineStatus;
44 using update_engine::UpdateStatus;
45 
46 namespace chromeos_update_engine {
47 namespace {
48 
49 class SideloadDaemonState : public DaemonStateInterface,
50                             public ServiceObserverInterface {
51  public:
SideloadDaemonState(brillo::StreamPtr status_stream)52   explicit SideloadDaemonState(brillo::StreamPtr status_stream)
53       : status_stream_(std::move(status_stream)) {
54     // Add this class as the only observer.
55     observers_.insert(this);
56   }
57   ~SideloadDaemonState() override = default;
58 
59   // DaemonStateInterface overrides.
StartUpdater()60   bool StartUpdater() override { return true; }
AddObserver(ServiceObserverInterface * observer)61   void AddObserver(ServiceObserverInterface* observer) override {}
RemoveObserver(ServiceObserverInterface * observer)62   void RemoveObserver(ServiceObserverInterface* observer) override {}
service_observers()63   const std::set<ServiceObserverInterface*>& service_observers() override {
64     return observers_;
65   }
66 
67   // ServiceObserverInterface overrides.
SendStatusUpdate(const UpdateEngineStatus & update_engine_status)68   void SendStatusUpdate(
69       const UpdateEngineStatus& update_engine_status) override {
70     UpdateStatus status = update_engine_status.status;
71     double progress = update_engine_status.progress;
72     if (status_ != status && (status == UpdateStatus::DOWNLOADING ||
73                               status == UpdateStatus::FINALIZING)) {
74       // Split the progress bar in two parts for the two stages DOWNLOADING and
75       // FINALIZING.
76       ReportStatus(base::StringPrintf(
77           "ui_print Step %d/2", status == UpdateStatus::DOWNLOADING ? 1 : 2));
78       ReportStatus(base::StringPrintf("progress 0.5 0"));
79     }
80     if (status_ != status || fabs(progress - progress_) > 0.005) {
81       ReportStatus(base::StringPrintf("set_progress %.lf", progress));
82     }
83     progress_ = progress;
84     status_ = status;
85   }
86 
SendPayloadApplicationComplete(ErrorCode error_code)87   void SendPayloadApplicationComplete(ErrorCode error_code) override {
88     if (error_code != ErrorCode::kSuccess) {
89       ReportStatus(
90           base::StringPrintf("ui_print Error applying update: %d (%s)",
91                              error_code,
92                              utils::ErrorCodeToString(error_code).c_str()));
93     }
94     error_code_ = error_code;
95     brillo::MessageLoop::current()->BreakLoop();
96   }
97 
98   // Getters.
status()99   UpdateStatus status() { return status_; }
error_code()100   ErrorCode error_code() { return error_code_; }
101 
102  private:
103   // Report a status message in the status_stream_, if any. These messages
104   // should conform to the specification defined in the Android recovery.
ReportStatus(const string & message)105   void ReportStatus(const string& message) {
106     if (!status_stream_)
107       return;
108     string status_line = message + "\n";
109     status_stream_->WriteAllBlocking(
110         status_line.data(), status_line.size(), nullptr);
111   }
112 
113   std::set<ServiceObserverInterface*> observers_;
114   brillo::StreamPtr status_stream_;
115 
116   // The last status and error code reported.
117   UpdateStatus status_{UpdateStatus::IDLE};
118   ErrorCode error_code_{ErrorCode::kSuccess};
119   double progress_{-1.};
120 };
121 
122 // Apply an update payload directly from the given payload URI.
ApplyUpdatePayload(const string & payload,int64_t payload_offset,int64_t payload_size,const vector<string> & headers,int64_t status_fd)123 bool ApplyUpdatePayload(const string& payload,
124                         int64_t payload_offset,
125                         int64_t payload_size,
126                         const vector<string>& headers,
127                         int64_t status_fd) {
128   brillo::BaseMessageLoop loop;
129   loop.SetAsCurrent();
130 
131   // Setup the subprocess handler.
132   brillo::AsynchronousSignalHandler handler;
133   handler.Init();
134   Subprocess subprocess;
135   subprocess.Init(&handler);
136 
137   SideloadDaemonState sideload_daemon_state(
138       brillo::FileStream::FromFileDescriptor(status_fd, true, nullptr));
139 
140   // During the sideload we don't access the prefs persisted on disk but instead
141   // use a temporary memory storage.
142   MemoryPrefs prefs;
143 
144   std::unique_ptr<BootControlInterface> boot_control =
145       boot_control::CreateBootControl();
146   if (!boot_control) {
147     LOG(ERROR) << "Error initializing the BootControlInterface.";
148     return false;
149   }
150 
151   std::unique_ptr<HardwareInterface> hardware = hardware::CreateHardware();
152   if (!hardware) {
153     LOG(ERROR) << "Error initializing the HardwareInterface.";
154     return false;
155   }
156 
157   UpdateAttempterAndroid update_attempter(
158       &sideload_daemon_state, &prefs, boot_control.get(), hardware.get());
159   update_attempter.Init();
160 
161   TEST_AND_RETURN_FALSE(update_attempter.ApplyPayload(
162       payload, payload_offset, payload_size, headers, nullptr));
163 
164   loop.Run();
165   return sideload_daemon_state.status() == UpdateStatus::UPDATED_NEED_REBOOT;
166 }
167 
168 }  // namespace
169 }  // namespace chromeos_update_engine
170 
main(int argc,char ** argv)171 int main(int argc, char** argv) {
172   DEFINE_string(payload,
173                 "file:///data/payload.bin",
174                 "The URI to the update payload to use.");
175   DEFINE_int64(
176       offset, 0, "The offset in the payload where the CrAU update starts. ");
177   DEFINE_int64(size,
178                0,
179                "The size of the CrAU part of the payload. If 0 is passed, it "
180                "will be autodetected.");
181   DEFINE_string(headers,
182                 "",
183                 "A list of key-value pairs, one element of the list per line.");
184   DEFINE_int64(status_fd, -1, "A file descriptor to notify the update status.");
185 
186   chromeos_update_engine::Terminator::Init();
187   chromeos_update_engine::SetupLogging(true /* stderr */, false /* file */);
188   brillo::FlagHelper::Init(argc, argv, "Update Engine Sideload");
189 
190   LOG(INFO) << "Update Engine Sideloading starting";
191 
192   // xz-embedded requires to initialize its CRC-32 table once on startup.
193   xz_crc32_init();
194 
195   vector<string> headers = base::SplitString(
196       FLAGS_headers, "\n", base::KEEP_WHITESPACE, base::SPLIT_WANT_NONEMPTY);
197 
198   if (!chromeos_update_engine::ApplyUpdatePayload(
199           FLAGS_payload, FLAGS_offset, FLAGS_size, headers, FLAGS_status_fd))
200     return 1;
201 
202   return 0;
203 }
204