blob: 3d916c48df7c32d4b3ec64749b370562c5df626b [file] [log] [blame]
Martijn Coenencabc92f2019-01-11 10:50:35 +01001/*
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
Martijn Coenenc11b68b2019-01-15 11:28:11 +010017#include "apexd_session.h"
Andreas Gampef35e1792019-04-01 15:58:03 -070018
Martijn Coenen610909b2019-01-18 13:49:38 +010019#include "apexd_utils.h"
Martijn Coenencabc92f2019-01-11 10:50:35 +010020#include "string_log.h"
21
22#include "session_state.pb.h"
23
24#include <android-base/logging.h>
Martijn Coenen610909b2019-01-18 13:49:38 +010025#include <dirent.h>
Martijn Coenencabc92f2019-01-11 10:50:35 +010026#include <sys/stat.h>
27
Nikita Ioffe53c3dcd2019-02-08 17:39:00 +000028#include <filesystem>
Martijn Coenencabc92f2019-01-11 10:50:35 +010029#include <fstream>
Nikita Ioffe463d4e82019-02-10 18:46:20 +000030#include <optional>
Colin Cross7868c942019-08-13 15:31:00 -070031#include <utility>
Nikita Ioffe53c3dcd2019-02-08 17:39:00 +000032
Mohammad Samiul Islambd6ab0f2019-06-20 15:55:27 +010033using android::base::Error;
34using android::base::Result;
Martijn Coenencabc92f2019-01-11 10:50:35 +010035using apex::proto::SessionState;
36
37namespace android {
38namespace apex {
39
40namespace {
41
Martijn Coenend32d1cb2019-02-13 12:43:57 +010042static constexpr const char* kStateFileName = "state";
43
Martijn Coenen610909b2019-01-18 13:49:38 +010044std::string getSessionDir(int session_id) {
45 return kApexSessionsDir + "/" + std::to_string(session_id);
Martijn Coenencabc92f2019-01-11 10:50:35 +010046}
47
Martijn Coenen610909b2019-01-18 13:49:38 +010048std::string getSessionStateFilePath(int session_id) {
Martijn Coenend32d1cb2019-02-13 12:43:57 +010049 return getSessionDir(session_id) + "/" + kStateFileName;
Martijn Coenencabc92f2019-01-11 10:50:35 +010050}
51
Mohammad Samiul Islambd6ab0f2019-06-20 15:55:27 +010052Result<std::string> createSessionDirIfNeeded(int session_id) {
Martijn Coenencabc92f2019-01-11 10:50:35 +010053 // create /data/sessions
Nikita Ioffea8453da2019-01-30 21:29:13 +000054 auto res = createDirIfNeeded(kApexSessionsDir, 0700);
Bernie Innocentid04d5d02020-02-06 22:01:51 +090055 if (!res.ok()) {
Mohammad Samiul Islambd6ab0f2019-06-20 15:55:27 +010056 return res.error();
Martijn Coenencabc92f2019-01-11 10:50:35 +010057 }
Martijn Coenen610909b2019-01-18 13:49:38 +010058 // create /data/sessions/session_id
Martijn Coenencabc92f2019-01-11 10:50:35 +010059 std::string sessionDir = getSessionDir(session_id);
Nikita Ioffea8453da2019-01-30 21:29:13 +000060 res = createDirIfNeeded(sessionDir, 0700);
Bernie Innocentid04d5d02020-02-06 22:01:51 +090061 if (!res.ok()) {
Mohammad Samiul Islambd6ab0f2019-06-20 15:55:27 +010062 return res.error();
Martijn Coenencabc92f2019-01-11 10:50:35 +010063 }
64
Mohammad Samiul Islambd6ab0f2019-06-20 15:55:27 +010065 return sessionDir;
Martijn Coenencabc92f2019-01-11 10:50:35 +010066}
67
Mohammad Samiul Islambd6ab0f2019-06-20 15:55:27 +010068Result<void> deleteSessionDir(int session_id) {
Nikita Ioffe53c3dcd2019-02-08 17:39:00 +000069 std::string session_dir = getSessionDir(session_id);
70 LOG(DEBUG) << "Deleting " << session_dir;
71 auto path = std::filesystem::path(session_dir);
72 std::error_code error_code;
73 std::filesystem::remove_all(path, error_code);
74 if (error_code) {
Mohammad Samiul Islambd6ab0f2019-06-20 15:55:27 +010075 return Error() << "Failed to delete " << session_dir << " : "
76 << error_code.message();
Nikita Ioffe53c3dcd2019-02-08 17:39:00 +000077 }
Mohammad Samiul Islambd6ab0f2019-06-20 15:55:27 +010078 return {};
Nikita Ioffe53c3dcd2019-02-08 17:39:00 +000079}
80
Martijn Coenen610909b2019-01-18 13:49:38 +010081} // namespace
82
Colin Cross7868c942019-08-13 15:31:00 -070083ApexSession::ApexSession(SessionState state) : state_(std::move(state)) {}
Martijn Coenen610909b2019-01-18 13:49:38 +010084
Mohammad Samiul Islambd6ab0f2019-06-20 15:55:27 +010085Result<ApexSession> ApexSession::CreateSession(int session_id) {
Martijn Coenend32d1cb2019-02-13 12:43:57 +010086 SessionState state;
Martijn Coenen610909b2019-01-18 13:49:38 +010087 // Create session directory
88 auto sessionPath = createSessionDirIfNeeded(session_id);
Bernie Innocentid04d5d02020-02-06 22:01:51 +090089 if (!sessionPath.ok()) {
Mohammad Samiul Islambd6ab0f2019-06-20 15:55:27 +010090 return sessionPath.error();
Martijn Coenen610909b2019-01-18 13:49:38 +010091 }
Martijn Coenend32d1cb2019-02-13 12:43:57 +010092 state.set_id(session_id);
Martijn Coenen610909b2019-01-18 13:49:38 +010093
Mohammad Samiul Islambd6ab0f2019-06-20 15:55:27 +010094 return ApexSession(state);
Martijn Coenen610909b2019-01-18 13:49:38 +010095}
Mohammad Samiul Islambd6ab0f2019-06-20 15:55:27 +010096Result<ApexSession> ApexSession::GetSessionFromFile(const std::string& path) {
Martijn Coenen610909b2019-01-18 13:49:38 +010097 SessionState state;
Martijn Coenen610909b2019-01-18 13:49:38 +010098 std::fstream stateFile(path, std::ios::in | std::ios::binary);
99 if (!stateFile) {
Mohammad Samiul Islambd6ab0f2019-06-20 15:55:27 +0100100 return Error() << "Failed to open " << path;
Martijn Coenencabc92f2019-01-11 10:50:35 +0100101 }
102
Martijn Coenen610909b2019-01-18 13:49:38 +0100103 if (!state.ParseFromIstream(&stateFile)) {
Mohammad Samiul Islambd6ab0f2019-06-20 15:55:27 +0100104 return Error() << "Failed to parse " << path;
Martijn Coenen610909b2019-01-18 13:49:38 +0100105 }
106
Mohammad Samiul Islambd6ab0f2019-06-20 15:55:27 +0100107 return ApexSession(state);
Martijn Coenend32d1cb2019-02-13 12:43:57 +0100108}
109
Mohammad Samiul Islambd6ab0f2019-06-20 15:55:27 +0100110Result<ApexSession> ApexSession::GetSession(int session_id) {
Martijn Coenend32d1cb2019-02-13 12:43:57 +0100111 auto path = getSessionStateFilePath(session_id);
112
113 return GetSessionFromFile(path);
Martijn Coenen610909b2019-01-18 13:49:38 +0100114}
115
116std::vector<ApexSession> ApexSession::GetSessions() {
117 std::vector<ApexSession> sessions;
118
Mohammad Samiul Islambd6ab0f2019-06-20 15:55:27 +0100119 Result<std::vector<std::string>> sessionPaths = ReadDir(
Mohammad Samiul Islamd428a182019-03-19 14:36:24 +0000120 kApexSessionsDir, [](const std::filesystem::directory_entry& entry) {
121 std::error_code ec;
122 return entry.is_directory(ec);
Martijn Coenen610909b2019-01-18 13:49:38 +0100123 });
124
Bernie Innocentid04d5d02020-02-06 22:01:51 +0900125 if (!sessionPaths.ok()) {
Martijn Coenen610909b2019-01-18 13:49:38 +0100126 return sessions;
127 }
128
Nikita Ioffe6bea4e52019-02-10 22:46:05 +0000129 for (const std::string& sessionDirPath : *sessionPaths) {
Martijn Coenen610909b2019-01-18 13:49:38 +0100130 // Try to read session state
Martijn Coenend32d1cb2019-02-13 12:43:57 +0100131 auto session = GetSessionFromFile(sessionDirPath + "/" + kStateFileName);
Bernie Innocentid04d5d02020-02-06 22:01:51 +0900132 if (!session.ok()) {
Mohammad Samiul Islambd6ab0f2019-06-20 15:55:27 +0100133 LOG(WARNING) << session.error();
Martijn Coenen610909b2019-01-18 13:49:38 +0100134 continue;
135 }
136 sessions.push_back(std::move(*session));
137 }
138
139 return sessions;
140}
141
142std::vector<ApexSession> ApexSession::GetSessionsInState(
143 SessionState::State state) {
144 auto sessions = GetSessions();
145 sessions.erase(
146 std::remove_if(sessions.begin(), sessions.end(),
Yi Kongc7a78122019-03-08 14:31:24 -0800147 [&](const ApexSession &s) { return s.GetState() != state; }),
Martijn Coenen610909b2019-01-18 13:49:38 +0100148 sessions.end());
149
150 return sessions;
151}
152
Mohammad Samiul Islam2401ae12019-11-20 17:12:31 +0000153std::vector<ApexSession> ApexSession::GetActiveSessions() {
154 auto sessions = GetSessions();
155 std::vector<ApexSession> activeSessions;
156 for (const ApexSession& session : sessions) {
157 if (!session.IsFinalized() && session.GetState() != SessionState::UNKNOWN) {
158 activeSessions.push_back(session);
159 }
160 }
161 return activeSessions;
162}
163
Martijn Coenen610909b2019-01-18 13:49:38 +0100164SessionState::State ApexSession::GetState() const { return state_.state(); }
165
Martijn Coenend32d1cb2019-02-13 12:43:57 +0100166int ApexSession::GetId() const { return state_.id(); }
Martijn Coenen610909b2019-01-18 13:49:38 +0100167
Gavin Corkery778cace2019-09-26 12:53:45 +0100168std::string ApexSession::GetBuildFingerprint() const {
169 return state_.expected_build_fingerprint();
170}
171
Nikita Ioffe463d4e82019-02-10 18:46:20 +0000172bool ApexSession::IsFinalized() const {
173 switch (GetState()) {
174 case SessionState::SUCCESS:
Nikita Ioffe463d4e82019-02-10 18:46:20 +0000175 case SessionState::ACTIVATION_FAILED:
Mohammad Samiul Islamca852e32019-11-20 13:37:14 +0000176 case SessionState::REVERTED:
Mohammad Samiul Islamca852e32019-11-20 13:37:14 +0000177 case SessionState::REVERT_FAILED:
Nikita Ioffe463d4e82019-02-10 18:46:20 +0000178 return true;
179 default:
180 return false;
181 }
182}
183
Oli Lan123d9d02019-12-02 14:08:24 +0000184bool ApexSession::HasRollbackEnabled() const {
185 return state_.rollback_enabled();
186}
187
188bool ApexSession::IsRollback() const { return state_.is_rollback(); }
189
190int ApexSession::GetRollbackId() const { return state_.rollback_id(); }
191
Gavin Corkery92cd7b82020-01-13 12:35:38 +0000192std::string ApexSession::GetCrashingNativeProcess() const {
193 return state_.crashing_native_process();
194}
195
Dario Freni6dd4dd62019-01-18 12:45:44 +0000196const google::protobuf::RepeatedField<int> ApexSession::GetChildSessionIds()
197 const {
198 return state_.child_session_ids();
199}
200
201void ApexSession::SetChildSessionIds(
202 const std::vector<int>& child_session_ids) {
203 *(state_.mutable_child_session_ids()) = {child_session_ids.begin(),
204 child_session_ids.end()};
205}
206
Oli Lana18705f2020-01-18 14:35:46 +0000207const google::protobuf::RepeatedPtrField<std::string>
208ApexSession::GetApexNames() const {
209 return state_.apex_names();
210}
211
Gavin Corkery778cace2019-09-26 12:53:45 +0100212void ApexSession::SetBuildFingerprint(const std::string& fingerprint) {
213 *(state_.mutable_expected_build_fingerprint()) = fingerprint;
214}
215
Oli Lan123d9d02019-12-02 14:08:24 +0000216void ApexSession::SetHasRollbackEnabled(const bool enabled) {
217 state_.set_rollback_enabled(enabled);
218}
219
220void ApexSession::SetIsRollback(const bool is_rollback) {
221 state_.set_is_rollback(is_rollback);
222}
223
224void ApexSession::SetRollbackId(const int rollback_id) {
225 state_.set_rollback_id(rollback_id);
226}
227
Gavin Corkery92cd7b82020-01-13 12:35:38 +0000228void ApexSession::SetCrashingNativeProcess(
229 const std::string& crashing_process) {
230 state_.set_crashing_native_process(crashing_process);
231}
232
Oli Lana18705f2020-01-18 14:35:46 +0000233void ApexSession::AddApexName(const std::string& apex_name) {
234 state_.add_apex_names(apex_name);
235}
236
Mohammad Samiul Islambd6ab0f2019-06-20 15:55:27 +0100237Result<void> ApexSession::UpdateStateAndCommit(
Nikita Ioffea0c0ccb2019-02-12 22:00:41 +0000238 const SessionState::State& session_state) {
Martijn Coenen610909b2019-01-18 13:49:38 +0100239 state_.set_state(session_state);
240
Martijn Coenend32d1cb2019-02-13 12:43:57 +0100241 auto stateFilePath = getSessionStateFilePath(state_.id());
Martijn Coenen610909b2019-01-18 13:49:38 +0100242
Martijn Coenencabc92f2019-01-11 10:50:35 +0100243 std::fstream stateFile(stateFilePath,
244 std::ios::out | std::ios::trunc | std::ios::binary);
Martijn Coenen610909b2019-01-18 13:49:38 +0100245 if (!state_.SerializeToOstream(&stateFile)) {
Mohammad Samiul Islambd6ab0f2019-06-20 15:55:27 +0100246 return Error() << "Failed to write state file " << stateFilePath;
Martijn Coenencabc92f2019-01-11 10:50:35 +0100247 }
248
Mohammad Samiul Islambd6ab0f2019-06-20 15:55:27 +0100249 return {};
Martijn Coenencabc92f2019-01-11 10:50:35 +0100250}
251
Mohammad Samiul Islambd6ab0f2019-06-20 15:55:27 +0100252Result<void> ApexSession::DeleteSession() const {
253 return deleteSessionDir(GetId());
254}
Nikita Ioffe53c3dcd2019-02-08 17:39:00 +0000255
Nikita Ioffea0c0ccb2019-02-12 22:00:41 +0000256std::ostream& operator<<(std::ostream& out, const ApexSession& session) {
257 return out << "[id = " << session.GetId()
258 << "; state = " << SessionState::State_Name(session.GetState())
259 << "]";
260}
261
Martijn Coenencabc92f2019-01-11 10:50:35 +0100262} // namespace apex
263} // namespace android