mirror of
https://github.com/Atmosphere-NX/Atmosphere.git
synced 2025-07-17 14:22:13 +02:00
ncm: more install task progress
This commit is contained in:
parent
f2e3cee1f9
commit
0bf39a3bdf
@ -72,16 +72,14 @@ namespace ams::ncm {
|
|||||||
u8 attributes;
|
u8 attributes;
|
||||||
u8 storage_id;
|
u8 storage_id;
|
||||||
ContentInstallType install_type;
|
ContentInstallType install_type;
|
||||||
u8 reserved_17;
|
bool committed;
|
||||||
u32 required_download_system_version;
|
u32 required_download_system_version;
|
||||||
u8 reserved_1C[4];
|
u8 reserved_1C[4];
|
||||||
};
|
};
|
||||||
static_assert(sizeof(PackagedContentMetaHeader) == 0x20);
|
static_assert(sizeof(PackagedContentMetaHeader) == 0x20);
|
||||||
static_assert(OFFSETOF(PackagedContentMetaHeader, reserved_0D) == 0x0D);
|
static_assert(OFFSETOF(PackagedContentMetaHeader, reserved_0D) == 0x0D);
|
||||||
static_assert(OFFSETOF(PackagedContentMetaHeader, reserved_17) == 0x17);
|
|
||||||
static_assert(OFFSETOF(PackagedContentMetaHeader, reserved_1C) == 0x1C);
|
static_assert(OFFSETOF(PackagedContentMetaHeader, reserved_1C) == 0x1C);
|
||||||
|
|
||||||
/* TODO: Confirm this is correct. */
|
|
||||||
using InstallContentMetaHeader = PackagedContentMetaHeader;
|
using InstallContentMetaHeader = PackagedContentMetaHeader;
|
||||||
|
|
||||||
struct ApplicationMetaExtendedHeader {
|
struct ApplicationMetaExtendedHeader {
|
||||||
@ -294,6 +292,10 @@ namespace ams::ncm {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
StorageId GetStorageId() const {
|
||||||
|
return static_cast<StorageId>(this->GetHeader()->storage_id);
|
||||||
|
}
|
||||||
|
|
||||||
std::optional<ApplicationId> GetApplicationId(const ContentMetaKey &key) const {
|
std::optional<ApplicationId> GetApplicationId(const ContentMetaKey &key) const {
|
||||||
switch (key.type) {
|
switch (key.type) {
|
||||||
case ContentMetaType::Application: return ApplicationId{ key.id };
|
case ContentMetaType::Application: return ApplicationId{ key.id };
|
||||||
|
@ -19,13 +19,19 @@
|
|||||||
namespace ams::ncm {
|
namespace ams::ncm {
|
||||||
|
|
||||||
/* protected:
|
/* protected:
|
||||||
PrepareContentMeta (both), WritePlaceHolderBuffer, PrepareAgain, Get/Delete InstallContentMetaData, PrepareDependency, PrepareSystemDependency, PrepareContentMetaIfLatest, GetConfig, WriteContentMetaToPlaceHolder, GetInstallStorage, GetSystemUpdateTaskApplyInfo, CanContinue
|
PrepareContentMeta (both), WritePlaceHolderBuffer, Get/Delete InstallContentMetaData, PrepareDependency, PrepareSystemDependency, PrepareContentMetaIfLatest, GetConfig, WriteContentMetaToPlaceHolder, GetInstallStorage, GetSystemUpdateTaskApplyInfo, CanContinue
|
||||||
*/
|
*/
|
||||||
struct InstallThroughput {
|
struct InstallThroughput {
|
||||||
s64 installed;
|
s64 installed;
|
||||||
TimeSpan elapsed_time;
|
TimeSpan elapsed_time;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum class ListContentMetaKeyFilter : u8 {
|
||||||
|
All = 0,
|
||||||
|
Committed = 1,
|
||||||
|
NotCommitted = 2,
|
||||||
|
};
|
||||||
|
|
||||||
class InstallTaskBase {
|
class InstallTaskBase {
|
||||||
private:
|
private:
|
||||||
crypto::Sha256Generator sha256_generator;
|
crypto::Sha256Generator sha256_generator;
|
||||||
@ -48,6 +54,8 @@ PrepareContentMeta (both), WritePlaceHolderBuffer, PrepareAgain, Get/Delete Inst
|
|||||||
Result Initialize(StorageId install_storage, InstallTaskDataBase *data, u32 config);
|
Result Initialize(StorageId install_storage, InstallTaskDataBase *data, u32 config);
|
||||||
Result CountInstallContentMetaData(s32 *out_count);
|
Result CountInstallContentMetaData(s32 *out_count);
|
||||||
Result GetInstallContentMetaData(InstallContentMeta *out_content_meta, s32 index);
|
Result GetInstallContentMetaData(InstallContentMeta *out_content_meta, s32 index);
|
||||||
|
|
||||||
|
void PrepareAgain();
|
||||||
public:
|
public:
|
||||||
/* TODO: Fix access types. */
|
/* TODO: Fix access types. */
|
||||||
bool IsCancelRequested();
|
bool IsCancelRequested();
|
||||||
@ -57,8 +65,19 @@ PrepareContentMeta (both), WritePlaceHolderBuffer, PrepareAgain, Get/Delete Inst
|
|||||||
Result CalculateRequiredSize(size_t *out_size);
|
Result CalculateRequiredSize(size_t *out_size);
|
||||||
void ResetThroughputMeasurement();
|
void ResetThroughputMeasurement();
|
||||||
void SetProgressState(InstallProgressState state);
|
void SetProgressState(InstallProgressState state);
|
||||||
|
|
||||||
|
void UpdateThroughputMeasurement(s64 throughput);
|
||||||
|
bool IsNecessaryInstallTicket(const fs::RightsId &rights_id);
|
||||||
void SetTotalSize(s64 size);
|
void SetTotalSize(s64 size);
|
||||||
Result PreparePlaceHolder();
|
Result PreparePlaceHolder();
|
||||||
|
Result Cleanup();
|
||||||
|
Result CleanupOne(const InstallContentMeta &content_meta);
|
||||||
|
void CleanupProgress();
|
||||||
|
Result ListContentMetaKey(s32 *out_keys_written, StorageContentMetaKey *out_keys, s32 out_keys_count, s32 offset, ListContentMetaKeyFilter filter);
|
||||||
|
Result ListApplicationContentMetaKey(s32 *out_keys_written, ApplicationContentMetaKey *out_keys, s32 out_keys_count, s32 offset);
|
||||||
|
|
||||||
|
void ResetLastResult();
|
||||||
|
s64 GetThroughput();
|
||||||
protected:
|
protected:
|
||||||
virtual Result OnPrepareComplete();
|
virtual Result OnPrepareComplete();
|
||||||
virtual Result PrepareDependency();
|
virtual Result PrepareDependency();
|
||||||
|
@ -194,7 +194,8 @@ namespace ams::ncm {
|
|||||||
std::scoped_lock lk(placeholder_mutex);
|
std::scoped_lock lk(placeholder_mutex);
|
||||||
|
|
||||||
InstallContentMeta content_meta;
|
InstallContentMeta content_meta;
|
||||||
if (R_SUCCEEDED(this->data->Get(&content_meta, i))) {
|
R_TRY(this->data->Get(&content_meta, i));
|
||||||
|
|
||||||
auto writer = content_meta.GetWriter();
|
auto writer = content_meta.GetWriter();
|
||||||
StorageId storage_id = static_cast<StorageId>(writer.GetHeader()->storage_id);
|
StorageId storage_id = static_cast<StorageId>(writer.GetHeader()->storage_id);
|
||||||
|
|
||||||
@ -217,6 +218,7 @@ namespace ams::ncm {
|
|||||||
R_UNLESS(!this->IsCancelRequested(), ncm::ResultCreatePlaceHolderCancelled());
|
R_UNLESS(!this->IsCancelRequested(), ncm::ResultCreatePlaceHolderCancelled());
|
||||||
auto *content_info = writer.GetWritableContentInfo(j);
|
auto *content_info = writer.GetWritableContentInfo(j);
|
||||||
|
|
||||||
|
/* Check if we have the content already exists. */
|
||||||
bool has_content;
|
bool has_content;
|
||||||
R_TRY(content_storage.Has(&has_content, content_info->GetId()));
|
R_TRY(content_storage.Has(&has_content, content_info->GetId()));
|
||||||
|
|
||||||
@ -251,14 +253,188 @@ namespace ams::ncm {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
this->SetTotalSize(total_size);
|
this->SetTotalSize(total_size);
|
||||||
return ResultSuccess();
|
return ResultSuccess();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Result InstallTaskBase::Cleanup() {
|
||||||
|
/* Count the number of content meta entries. */
|
||||||
|
s32 count;
|
||||||
|
R_TRY(this->data->Count(std::addressof(count)));
|
||||||
|
|
||||||
|
/* Iterate over content meta. */
|
||||||
|
for (s32 i = 0; i < count; i++) {
|
||||||
|
/* Get the content meta. */
|
||||||
|
InstallContentMeta content_meta;
|
||||||
|
R_TRY(this->data->Get(&content_meta, i));
|
||||||
|
|
||||||
|
/* Cleanup the content meta. */
|
||||||
|
/* N doesn't check the result of this. */
|
||||||
|
this->CleanupOne(content_meta);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Cleanup the data and progress. */
|
||||||
|
R_TRY(this->data->Cleanup());
|
||||||
|
this->CleanupProgress();
|
||||||
|
return ResultSuccess();
|
||||||
|
}
|
||||||
|
|
||||||
|
Result InstallTaskBase::CleanupOne(const InstallContentMeta &content_meta) {
|
||||||
|
/* Obtain a reader and get the storage id. */
|
||||||
|
const auto reader = content_meta.GetReader();
|
||||||
|
R_SUCCEED_IF(reader.GetStorageId() == StorageId::None);
|
||||||
|
|
||||||
|
/* Open the relevant content storage. */
|
||||||
|
ContentStorage content_storage;
|
||||||
|
R_TRY(ncm::OpenContentStorage(&content_storage, reader.GetStorageId()));
|
||||||
|
|
||||||
|
/* Iterate over content infos. */
|
||||||
|
for (size_t i = 0; i < reader.GetContentCount(); i++) {
|
||||||
|
auto *content_info = reader.GetContentInfo(i);
|
||||||
|
|
||||||
|
/* Delete placeholders for Prepared or Installed content infos. */
|
||||||
|
if (content_info->install_state == InstallState::Prepared || content_info->install_state == InstallState::Installed) {
|
||||||
|
content_storage.DeletePlaceHolder(content_info->placeholder_id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return ResultSuccess();
|
||||||
|
}
|
||||||
|
|
||||||
|
void InstallTaskBase::CleanupProgress() {
|
||||||
|
std::scoped_lock(this->progress_mutex);
|
||||||
|
this->progress.installed_size = 0;
|
||||||
|
this->progress.total_size = 0;
|
||||||
|
this->progress.state = InstallProgressState::NotPrepared;
|
||||||
|
this->progress.SetLastResult(ResultSuccess());
|
||||||
|
}
|
||||||
|
|
||||||
|
Result InstallTaskBase::ListContentMetaKey(s32 *out_keys_written, StorageContentMetaKey *out_keys, s32 out_keys_count, s32 offset, ListContentMetaKeyFilter filter) {
|
||||||
|
/* Count the number of content meta entries. */
|
||||||
|
s32 count;
|
||||||
|
R_TRY(this->data->Count(std::addressof(count)));
|
||||||
|
|
||||||
|
/* Offset exceeds keys that can be written. */
|
||||||
|
if (count <= offset) {
|
||||||
|
*out_keys_written = 0;
|
||||||
|
return ResultSuccess();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (filter == ListContentMetaKeyFilter::All) {
|
||||||
|
const size_t num_keys = std::min(count, offset + out_keys_count);
|
||||||
|
|
||||||
|
/* Iterate over content meta. */
|
||||||
|
for (s32 i = offset; i < num_keys; i++) {
|
||||||
|
/* Obtain the content meta. */
|
||||||
|
InstallContentMeta content_meta;
|
||||||
|
R_TRY(this->data->Get(&content_meta, i));
|
||||||
|
|
||||||
|
/* Write output StorageContentMetaKey. */
|
||||||
|
const auto reader = content_meta.GetReader();
|
||||||
|
StorageContentMetaKey &storage_key = out_keys[i - offset];
|
||||||
|
storage_key.key = reader.GetKey();
|
||||||
|
storage_key.storage_id = reader.GetStorageId();
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Output the number of keys written. */
|
||||||
|
*out_keys_written = num_keys - offset;
|
||||||
|
} else {
|
||||||
|
s32 keys_written = 0;
|
||||||
|
s32 curr_offset = 0;
|
||||||
|
|
||||||
|
/* Iterate over content meta. */
|
||||||
|
for (s32 i = 0; i < count; i++) {
|
||||||
|
/* Obtain the content meta. */
|
||||||
|
InstallContentMeta content_meta;
|
||||||
|
R_TRY(this->data->Get(&content_meta, i));
|
||||||
|
|
||||||
|
/* Create a reader and check if the content has been committed. */
|
||||||
|
const auto reader = content_meta.GetReader();
|
||||||
|
const bool committed = reader.GetHeader()->committed;
|
||||||
|
|
||||||
|
/* Apply filter. */
|
||||||
|
if ((!committed && filter == ListContentMetaKeyFilter::Committed) || (committed && filter == ListContentMetaKeyFilter::NotCommitted)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Write output StorageContentMetaKey if at a suitable offset. */
|
||||||
|
if (curr_offset >= offset) {
|
||||||
|
StorageContentMetaKey &storage_key = out_keys[keys_written++];
|
||||||
|
storage_key.key = reader.GetKey();
|
||||||
|
storage_key.storage_id = reader.GetStorageId();
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Increment the current offset. */
|
||||||
|
curr_offset++;
|
||||||
|
|
||||||
|
/* We can't write any more output keys. */
|
||||||
|
if (keys_written >= out_keys_count) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Output the number of keys written. */
|
||||||
|
*out_keys_written = keys_written;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ResultSuccess();
|
||||||
|
}
|
||||||
|
|
||||||
|
Result InstallTaskBase::ListApplicationContentMetaKey(s32 *out_keys_written, ApplicationContentMetaKey *out_keys, s32 out_keys_count, s32 offset) {
|
||||||
|
/* Count the number of content meta entries. */
|
||||||
|
s32 count;
|
||||||
|
R_TRY(this->data->Count(std::addressof(count)));
|
||||||
|
|
||||||
|
s32 keys_written = 0;
|
||||||
|
|
||||||
|
/* Iterate over content meta. */
|
||||||
|
for (s32 i = offset; i < std::min(count, offset + out_keys_count); i++) {
|
||||||
|
/* Obtain the content meta. */
|
||||||
|
InstallContentMeta content_meta;
|
||||||
|
R_TRY(this->data->Get(&content_meta, i));
|
||||||
|
|
||||||
|
/* Create a reader. */
|
||||||
|
const auto reader = content_meta.GetReader();
|
||||||
|
|
||||||
|
/* Ensure this key has an application id. */
|
||||||
|
if (!reader.GetApplicationId()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Write output ApplicationContentMetaKey. */
|
||||||
|
ApplicationContentMetaKey &out_key = out_keys[keys_written++];
|
||||||
|
out_key.key = reader.GetKey();
|
||||||
|
out_key.application_id = *reader.GetApplicationId();
|
||||||
|
}
|
||||||
|
|
||||||
|
*out_keys_written = keys_written;
|
||||||
|
return ResultSuccess();
|
||||||
|
}
|
||||||
|
|
||||||
/* ... */
|
/* ... */
|
||||||
|
|
||||||
|
void InstallTaskBase::UpdateThroughputMeasurement(s64 throughput) {
|
||||||
|
std::scoped_lock lk(this->throughput_mutex);
|
||||||
|
|
||||||
|
if (this->throughput_start_time.GetNanoSeconds() != 0) {
|
||||||
|
this->throughput.installed += throughput;
|
||||||
|
/* TODO. */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool InstallTaskBase::IsNecessaryInstallTicket(const fs::RightsId &rights_id) {
|
||||||
|
/* If the title has no rights, there's no ticket to install. */
|
||||||
|
fs::RightsId empty_rights_id = {};
|
||||||
|
if (std::memcmp(std::addressof(rights_id), std::addressof(empty_rights_id), sizeof(fs::RightsId)) == 0) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* TODO: Support detecting if a title requires rights. */
|
||||||
|
/* TODO: How should es be handled without undesired effects? */
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
void InstallTaskBase::SetTotalSize(s64 size) {
|
void InstallTaskBase::SetTotalSize(s64 size) {
|
||||||
std::scoped_lock(this->progress_mutex);
|
std::scoped_lock(this->progress_mutex);
|
||||||
this->progress.total_size = size;
|
this->progress.total_size = size;
|
||||||
@ -266,6 +442,10 @@ namespace ams::ncm {
|
|||||||
|
|
||||||
/* ... */
|
/* ... */
|
||||||
|
|
||||||
|
void InstallTaskBase::PrepareAgain() {
|
||||||
|
this->SetProgressState(InstallProgressState::NotPrepared);
|
||||||
|
}
|
||||||
|
|
||||||
Result InstallTaskBase::PrepareDependency() {
|
Result InstallTaskBase::PrepareDependency() {
|
||||||
return ResultSuccess();
|
return ResultSuccess();
|
||||||
}
|
}
|
||||||
@ -276,4 +456,14 @@ namespace ams::ncm {
|
|||||||
std::scoped_lock lk(this->progress_mutex);
|
std::scoped_lock lk(this->progress_mutex);
|
||||||
return this->progress;
|
return this->progress;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void InstallTaskBase::ResetLastResult() {
|
||||||
|
this->SetLastResult(ResultSuccess());
|
||||||
|
}
|
||||||
|
|
||||||
|
s64 InstallTaskBase::GetThroughput() {
|
||||||
|
std::scoped_lock lk(this->throughput_mutex);
|
||||||
|
return this->throughput.installed;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user