blob: 8279eb857f3325672d1670c7c8884d2671b4ff58 [file] [log] [blame]
// Copyright 2020 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "src/modular/bin/basemgr/sessions.h"
#include <lib/syslog/cpp/macros.h>
#include "src/lib/files/directory.h"
#include "src/lib/files/path.h"
#include "src/modular/bin/basemgr/cobalt/cobalt.h"
namespace modular::sessions {
// The path containing a subdirectory for each session.
constexpr char kSessionDirectoryLocation[] = "/data/modular";
// A standard prefix used on every session directory.
// Note: This is named "USER_" for legacy reasons. SESSION_ may have been more
// appropriate but a change would require a data migration.
constexpr char kSessionDirectoryPrefix[] = "USER_";
// A fixed session ID that is used for new persistent sessions. This is possible
// as basemanager never creates more than a single persistent session per device.
constexpr char kStandardSessionId[] = "0";
std::string GetSessionDirectory(std::string_view session_id) {
return std::string(kSessionDirectoryLocation)
.append("/")
.append(kSessionDirectoryPrefix)
.append(session_id);
}
std::vector<std::string> GetExistingSessionIds() {
std::vector<std::string> dirs;
if (!files::ReadDirContents(kSessionDirectoryLocation, &dirs)) {
FX_LOGS(WARNING) << "Could not open session directory location.";
return std::vector<std::string>();
}
std::vector<std::string> output;
for (const auto& dir : dirs) {
if (strncmp(dir.c_str(), kSessionDirectoryPrefix, strlen(kSessionDirectoryPrefix)) == 0) {
auto session_id = dir.substr(strlen(kSessionDirectoryPrefix));
FX_LOGS(INFO) << "Found existing directory for session " << session_id;
output.push_back(session_id);
}
}
return output;
}
std::string GetRandomSessionId() {
uint32_t random_number = 0;
while (random_number == 0) {
zx_cprng_draw(&random_number, sizeof random_number);
}
return std::to_string(random_number);
}
std::string GetStableSessionId() { return kStandardSessionId; }
void ReportNewSessionToCobalt(std::string_view session_id) {
if (session_id != GetStableSessionId()) {
FX_LOGS(INFO) << "Creating session using random ID.";
ReportEvent(cobalt_registry::ModularLifetimeEventsMetricDimensionEventType::
CreateSessionNewEphemeralAccount);
return;
}
auto existing_sessions = GetExistingSessionIds();
auto stable_session_exists = std::find(existing_sessions.begin(), existing_sessions.end(),
GetStableSessionId()) != existing_sessions.end();
if (stable_session_exists) {
if (existing_sessions.size() > 1) {
FX_LOGS(ERROR) << "Creating session using existing account with fixed ID, but others exist. "
<< "Non-stable sessions should be deleted.";
ReportEvent(cobalt_registry::ModularLifetimeEventsMetricDimensionEventType::
CreateSessionUnverifiableFixedAccount);
} else {
FX_LOGS(INFO) << "Creating session using existing account with fixed ID.";
ReportEvent(cobalt_registry::ModularLifetimeEventsMetricDimensionEventType::
CreateSessionExistingFixedAccount);
}
} else {
FX_LOGS(INFO) << "Creating session using new persistent account with fixed ID.";
ReportEvent(cobalt_registry::ModularLifetimeEventsMetricDimensionEventType::
CreateSessionNewPersistentAccount);
}
}
// Deletes a session with the given ID, including its isolated storage and session directory.
// Does nothing if the Modular session directory for this session ID does not exist.
//
// |session_id| must not be the stable session ID.
//
// TODO(fxbug.dev/51752): Remove once there are no sessions with random IDs in use
void DeleteSession(std::string_view session_id, fuchsia::sys::Environment* const base_environment) {
FX_DCHECK(session_id != modular::sessions::GetStableSessionId())
<< "The standard stable session cannot be deleted.";
static constexpr char kSessionEnvironmentLabelPrefix[] = "session-";
const auto label = std::string(kSessionEnvironmentLabelPrefix).append(session_id);
auto session_dir = GetSessionDirectory(session_id);
if (!files::IsDirectory(session_dir)) {
FX_LOGS(WARNING) << "Modular session directory does not exist, not deleting session: "
<< session_dir;
return;
}
FX_LOGS(WARNING) << "DELETING LEGACY STABLE SESSION: " << label;
// Erase the isolated storage for the session by creating an environment with
// |delete_storage_on_death| and immediately killing it.
{
fuchsia::sys::EnvironmentPtr session_environment;
fuchsia::sys::EnvironmentControllerPtr session_environment_controller;
base_environment->CreateNestedEnvironment(
session_environment.NewRequest(), session_environment_controller.NewRequest(), label,
/*additional_services=*/nullptr,
{.inherit_parent_services = true, .delete_storage_on_death = true});
// The nested environment will be killed when the controller goes out of scope.
}
// Cleanup the entry under the modular sessions directory.
if (auto is_dir_deleted = files::DeletePath(session_dir, /*recursive=*/true); !is_dir_deleted) {
FX_LOGS(ERROR) << "Failed to delete Modular session directory: " << session_dir;
}
}
void DeleteSessionsWithRandomIds(fuchsia::sys::Environment* const base_environment) {
auto existing_sessions = GetExistingSessionIds();
// Enumerate the sessions erasing the contents of all but the standard one.
for (const auto& existing_session : existing_sessions) {
if (existing_session != std::string_view(kStandardSessionId)) {
DeleteSession(existing_session, base_environment);
}
}
}
} // namespace modular::sessions