Wire up the Skia persistent GPU related artifacts cache. (flutter/engine#6278)
Also teaches FML to create files and directories.
This commit is contained in:
@@ -35,10 +35,8 @@ std::unique_ptr<fml::Mapping> DirectoryAssetBundle::GetAsMapping(
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
auto mapping = std::make_unique<fml::FileMapping>(
|
||||
fml::OpenFile(descriptor_, asset_name.c_str(), fml::OpenPermission::kRead,
|
||||
false /* directory */),
|
||||
false /* executable */);
|
||||
auto mapping = std::make_unique<fml::FileMapping>(fml::OpenFile(
|
||||
descriptor_, asset_name.c_str(), false, fml::FilePermission::kRead));
|
||||
|
||||
if (mapping->GetMapping() == nullptr) {
|
||||
return nullptr;
|
||||
|
||||
@@ -532,11 +532,61 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
====================================================================================================
|
||||
LIBRARY: engine
|
||||
ORIGIN: ../../../flutter/fml/platform/darwin/scoped_block.h + ../../../LICENSE
|
||||
ORIGIN: ../../../flutter/fml/platform/android/paths_android.h + ../../../LICENSE
|
||||
TYPE: LicenseType.bsd
|
||||
FILE: ../../../flutter/fml/platform/darwin/scoped_block.h
|
||||
FILE: ../../../flutter/fml/base32.cc
|
||||
FILE: ../../../flutter/fml/base32.h
|
||||
FILE: ../../../flutter/fml/base32_unittest.cc
|
||||
FILE: ../../../flutter/fml/file.cc
|
||||
FILE: ../../../flutter/fml/file.h
|
||||
FILE: ../../../flutter/fml/file_unittest.cc
|
||||
FILE: ../../../flutter/fml/macros.h
|
||||
FILE: ../../../flutter/fml/mapping.cc
|
||||
FILE: ../../../flutter/fml/message.cc
|
||||
FILE: ../../../flutter/fml/message.h
|
||||
FILE: ../../../flutter/fml/message_unittests.cc
|
||||
FILE: ../../../flutter/fml/native_library.h
|
||||
FILE: ../../../flutter/fml/paths.cc
|
||||
FILE: ../../../flutter/fml/platform/android/paths_android.h
|
||||
FILE: ../../../flutter/fml/platform/fuchsia/paths_fuchsia.cc
|
||||
FILE: ../../../flutter/fml/platform/posix/file_posix.cc
|
||||
FILE: ../../../flutter/fml/platform/posix/native_library_posix.cc
|
||||
FILE: ../../../flutter/fml/platform/posix/paths_posix.cc
|
||||
FILE: ../../../flutter/fml/platform/win/errors_win.cc
|
||||
FILE: ../../../flutter/fml/platform/win/errors_win.h
|
||||
FILE: ../../../flutter/fml/platform/win/file_win.cc
|
||||
FILE: ../../../flutter/fml/platform/win/native_library_win.cc
|
||||
FILE: ../../../flutter/fml/platform/win/wstring_conversion.h
|
||||
FILE: ../../../flutter/fml/unique_fd.cc
|
||||
FILE: ../../../flutter/fml/unique_fd.h
|
||||
FILE: ../../../flutter/fml/unique_object.h
|
||||
FILE: ../../../flutter/lib/ui/isolate_name_server/isolate_name_server.cc
|
||||
FILE: ../../../flutter/lib/ui/isolate_name_server/isolate_name_server.h
|
||||
FILE: ../../../flutter/lib/ui/isolate_name_server/isolate_name_server_natives.cc
|
||||
FILE: ../../../flutter/lib/ui/isolate_name_server/isolate_name_server_natives.h
|
||||
FILE: ../../../flutter/lib/ui/plugins/callback_cache.cc
|
||||
FILE: ../../../flutter/lib/ui/plugins/callback_cache.h
|
||||
FILE: ../../../flutter/shell/common/isolate_configuration.cc
|
||||
FILE: ../../../flutter/shell/common/isolate_configuration.h
|
||||
FILE: ../../../flutter/shell/common/persistent_cache.cc
|
||||
FILE: ../../../flutter/shell/common/persistent_cache.h
|
||||
FILE: ../../../flutter/shell/platform/android/android_shell_holder.cc
|
||||
FILE: ../../../flutter/shell/platform/android/android_shell_holder.h
|
||||
FILE: ../../../flutter/shell/platform/android/platform_message_response_android.cc
|
||||
FILE: ../../../flutter/shell/platform/android/platform_message_response_android.h
|
||||
FILE: ../../../flutter/shell/platform/darwin/ios/framework/Source/FlutterAppDelegate_Internal.h
|
||||
FILE: ../../../flutter/shell/platform/darwin/ios/framework/Source/platform_message_response_darwin.h
|
||||
FILE: ../../../flutter/shell/platform/darwin/ios/framework/Source/platform_message_response_darwin.mm
|
||||
FILE: ../../../flutter/shell/platform/embedder/embedder_surface.cc
|
||||
FILE: ../../../flutter/shell/platform/embedder/embedder_surface.h
|
||||
FILE: ../../../flutter/shell/platform/embedder/embedder_surface_gl.cc
|
||||
FILE: ../../../flutter/shell/platform/embedder/embedder_surface_gl.h
|
||||
FILE: ../../../flutter/shell/platform/embedder/embedder_surface_software.cc
|
||||
FILE: ../../../flutter/shell/platform/embedder/embedder_surface_software.h
|
||||
FILE: ../../../flutter/shell/version/version.cc
|
||||
FILE: ../../../flutter/shell/version/version.h
|
||||
----------------------------------------------------------------------------------------------------
|
||||
Copyright (c) 2013 The Chromium Authors. All rights reserved.
|
||||
Copyright 2018 The Flutter Authors. All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are
|
||||
@@ -567,51 +617,11 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
====================================================================================================
|
||||
LIBRARY: engine
|
||||
ORIGIN: ../../../flutter/fml/platform/fuchsia/paths_fuchsia.cc + ../../../LICENSE
|
||||
ORIGIN: ../../../flutter/fml/platform/darwin/scoped_block.h + ../../../LICENSE
|
||||
TYPE: LicenseType.bsd
|
||||
FILE: ../../../flutter/fml/file.h
|
||||
FILE: ../../../flutter/fml/macros.h
|
||||
FILE: ../../../flutter/fml/mapping.cc
|
||||
FILE: ../../../flutter/fml/message.cc
|
||||
FILE: ../../../flutter/fml/message.h
|
||||
FILE: ../../../flutter/fml/message_unittests.cc
|
||||
FILE: ../../../flutter/fml/native_library.h
|
||||
FILE: ../../../flutter/fml/paths.cc
|
||||
FILE: ../../../flutter/fml/platform/fuchsia/paths_fuchsia.cc
|
||||
FILE: ../../../flutter/fml/platform/posix/file_posix.cc
|
||||
FILE: ../../../flutter/fml/platform/posix/native_library_posix.cc
|
||||
FILE: ../../../flutter/fml/platform/posix/paths_posix.cc
|
||||
FILE: ../../../flutter/fml/platform/win/file_win.cc
|
||||
FILE: ../../../flutter/fml/platform/win/native_library_win.cc
|
||||
FILE: ../../../flutter/fml/platform/win/wstring_conversion.h
|
||||
FILE: ../../../flutter/fml/unique_fd.cc
|
||||
FILE: ../../../flutter/fml/unique_fd.h
|
||||
FILE: ../../../flutter/fml/unique_object.h
|
||||
FILE: ../../../flutter/lib/ui/isolate_name_server/isolate_name_server.cc
|
||||
FILE: ../../../flutter/lib/ui/isolate_name_server/isolate_name_server.h
|
||||
FILE: ../../../flutter/lib/ui/isolate_name_server/isolate_name_server_natives.cc
|
||||
FILE: ../../../flutter/lib/ui/isolate_name_server/isolate_name_server_natives.h
|
||||
FILE: ../../../flutter/lib/ui/plugins/callback_cache.cc
|
||||
FILE: ../../../flutter/lib/ui/plugins/callback_cache.h
|
||||
FILE: ../../../flutter/shell/common/isolate_configuration.cc
|
||||
FILE: ../../../flutter/shell/common/isolate_configuration.h
|
||||
FILE: ../../../flutter/shell/platform/android/android_shell_holder.cc
|
||||
FILE: ../../../flutter/shell/platform/android/android_shell_holder.h
|
||||
FILE: ../../../flutter/shell/platform/android/platform_message_response_android.cc
|
||||
FILE: ../../../flutter/shell/platform/android/platform_message_response_android.h
|
||||
FILE: ../../../flutter/shell/platform/darwin/ios/framework/Source/FlutterAppDelegate_Internal.h
|
||||
FILE: ../../../flutter/shell/platform/darwin/ios/framework/Source/platform_message_response_darwin.h
|
||||
FILE: ../../../flutter/shell/platform/darwin/ios/framework/Source/platform_message_response_darwin.mm
|
||||
FILE: ../../../flutter/shell/platform/embedder/embedder_surface.cc
|
||||
FILE: ../../../flutter/shell/platform/embedder/embedder_surface.h
|
||||
FILE: ../../../flutter/shell/platform/embedder/embedder_surface_gl.cc
|
||||
FILE: ../../../flutter/shell/platform/embedder/embedder_surface_gl.h
|
||||
FILE: ../../../flutter/shell/platform/embedder/embedder_surface_software.cc
|
||||
FILE: ../../../flutter/shell/platform/embedder/embedder_surface_software.h
|
||||
FILE: ../../../flutter/shell/version/version.cc
|
||||
FILE: ../../../flutter/shell/version/version.h
|
||||
FILE: ../../../flutter/fml/platform/darwin/scoped_block.h
|
||||
----------------------------------------------------------------------------------------------------
|
||||
Copyright 2018 The Flutter Authors. All rights reserved.
|
||||
Copyright (c) 2013 The Chromium Authors. All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are
|
||||
|
||||
@@ -5,6 +5,8 @@
|
||||
source_set("fml") {
|
||||
sources = [
|
||||
"arraysize.h",
|
||||
"base32.cc",
|
||||
"base32.h",
|
||||
"build_config.h",
|
||||
"closure.h",
|
||||
"command_line.cc",
|
||||
@@ -12,6 +14,7 @@ source_set("fml") {
|
||||
"compiler_specific.h",
|
||||
"eintr_wrapper.h",
|
||||
"export.h",
|
||||
"file.cc",
|
||||
"file.h",
|
||||
"icu_util.cc",
|
||||
"icu_util.h",
|
||||
@@ -104,6 +107,7 @@ source_set("fml") {
|
||||
"platform/android/message_loop_android.cc",
|
||||
"platform/android/message_loop_android.h",
|
||||
"platform/android/paths_android.cc",
|
||||
"platform/android/paths_android.h",
|
||||
"platform/android/scoped_java_ref.cc",
|
||||
"platform/android/scoped_java_ref.h",
|
||||
]
|
||||
@@ -139,6 +143,8 @@ source_set("fml") {
|
||||
|
||||
if (is_win) {
|
||||
sources += [
|
||||
"platform/win/errors_win.cc",
|
||||
"platform/win/errors_win.h",
|
||||
"platform/win/file_win.cc",
|
||||
"platform/win/mapping_win.cc",
|
||||
"platform/win/message_loop_win.cc",
|
||||
@@ -161,7 +167,9 @@ executable("fml_unittests") {
|
||||
testonly = true
|
||||
|
||||
sources = [
|
||||
"base32_unittest.cc",
|
||||
"command_line_unittest.cc",
|
||||
"file_unittest.cc",
|
||||
"memory/ref_counted_unittest.cc",
|
||||
"memory/weak_ptr_unittest.cc",
|
||||
"message_loop_unittests.cc",
|
||||
|
||||
46
engine/src/flutter/fml/base32.cc
Normal file
46
engine/src/flutter/fml/base32.cc
Normal file
@@ -0,0 +1,46 @@
|
||||
// Copyright 2018 The Flutter 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 "flutter/fml/base32.h"
|
||||
|
||||
#include <limits>
|
||||
|
||||
#include "flutter/fml/macros.h"
|
||||
|
||||
namespace fml {
|
||||
|
||||
static constexpr char kEncoding[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567";
|
||||
|
||||
std::pair<bool, std::string> Base32Encode(StringView input) {
|
||||
if (input.empty()) {
|
||||
return {true, ""};
|
||||
}
|
||||
|
||||
if (input.size() > std::numeric_limits<size_t>::max() / 8) {
|
||||
return {false, ""};
|
||||
}
|
||||
|
||||
std::string output;
|
||||
const size_t encoded_length = (input.size() * 8 + 4) / 5;
|
||||
output.reserve(encoded_length);
|
||||
|
||||
uint16_t bit_stream = (static_cast<uint8_t>(input[0]) << 8);
|
||||
size_t next_byte_index = 1;
|
||||
int free_bits = 8;
|
||||
|
||||
while (free_bits < 16) {
|
||||
output.push_back(kEncoding[(bit_stream & 0xf800) >> 11]);
|
||||
bit_stream <<= 5;
|
||||
free_bits += 5;
|
||||
|
||||
if (free_bits >= 8 && next_byte_index < input.size()) {
|
||||
free_bits -= 8;
|
||||
bit_stream += static_cast<uint8_t>(input[next_byte_index++]) << free_bits;
|
||||
}
|
||||
}
|
||||
|
||||
return {true, output};
|
||||
}
|
||||
|
||||
} // namespace fml
|
||||
19
engine/src/flutter/fml/base32.h
Normal file
19
engine/src/flutter/fml/base32.h
Normal file
@@ -0,0 +1,19 @@
|
||||
// Copyright 2018 The Flutter Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#ifndef FLUTTER_FML_BASE32_H_
|
||||
#define FLUTTER_FML_BASE32_H_
|
||||
|
||||
#include <string>
|
||||
#include <utility>
|
||||
|
||||
#include "flutter/fml/string_view.h"
|
||||
|
||||
namespace fml {
|
||||
|
||||
std::pair<bool, std::string> Base32Encode(StringView input);
|
||||
|
||||
} // namespace fml
|
||||
|
||||
#endif // FLUTTER_FML_BASE32_H_
|
||||
38
engine/src/flutter/fml/base32_unittest.cc
Normal file
38
engine/src/flutter/fml/base32_unittest.cc
Normal file
@@ -0,0 +1,38 @@
|
||||
// Copyright 2018 The Flutter 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 "flutter/fml/base32.h"
|
||||
#include "gtest/gtest.h"
|
||||
|
||||
TEST(Base32Test, CanEncode) {
|
||||
{
|
||||
auto result = fml::Base32Encode("hello");
|
||||
ASSERT_TRUE(result.first);
|
||||
ASSERT_EQ(result.second, "NBSWY3DP");
|
||||
}
|
||||
|
||||
{
|
||||
auto result = fml::Base32Encode("helLo");
|
||||
ASSERT_TRUE(result.first);
|
||||
ASSERT_EQ(result.second, "NBSWYTDP");
|
||||
}
|
||||
|
||||
{
|
||||
auto result = fml::Base32Encode("");
|
||||
ASSERT_TRUE(result.first);
|
||||
ASSERT_EQ(result.second, "");
|
||||
}
|
||||
|
||||
{
|
||||
auto result = fml::Base32Encode("1");
|
||||
ASSERT_TRUE(result.first);
|
||||
ASSERT_EQ(result.second, "GE");
|
||||
}
|
||||
|
||||
{
|
||||
auto result = fml::Base32Encode("helLo");
|
||||
ASSERT_TRUE(result.first);
|
||||
ASSERT_EQ(result.second, "NBSWYTDP");
|
||||
}
|
||||
}
|
||||
46
engine/src/flutter/fml/file.cc
Normal file
46
engine/src/flutter/fml/file.cc
Normal file
@@ -0,0 +1,46 @@
|
||||
// Copyright 2018 The Flutter 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 "flutter/fml/file.h"
|
||||
|
||||
#include "flutter/fml/logging.h"
|
||||
|
||||
namespace fml {
|
||||
|
||||
static fml::UniqueFD CreateDirectory(const fml::UniqueFD& base_directory,
|
||||
const std::vector<std::string>& components,
|
||||
FilePermission permission,
|
||||
size_t index) {
|
||||
FML_DCHECK(index <= components.size());
|
||||
|
||||
const char* file_path = components[index].c_str();
|
||||
|
||||
auto directory = OpenDirectory(base_directory, file_path, true, permission);
|
||||
|
||||
if (!directory.is_valid()) {
|
||||
return {};
|
||||
}
|
||||
|
||||
if (index == components.size() - 1) {
|
||||
return directory;
|
||||
}
|
||||
|
||||
return CreateDirectory(directory, components, permission, index + 1);
|
||||
}
|
||||
|
||||
fml::UniqueFD CreateDirectory(const fml::UniqueFD& base_directory,
|
||||
const std::vector<std::string>& components,
|
||||
FilePermission permission) {
|
||||
if (!IsDirectory(base_directory)) {
|
||||
return {};
|
||||
}
|
||||
|
||||
if (components.size() == 0) {
|
||||
return {};
|
||||
}
|
||||
|
||||
return CreateDirectory(base_directory, components, permission, 0);
|
||||
}
|
||||
|
||||
} // namespace fml
|
||||
@@ -5,26 +5,46 @@
|
||||
#ifndef FLUTTER_FML_FILE_H_
|
||||
#define FLUTTER_FML_FILE_H_
|
||||
|
||||
#include <initializer_list>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "flutter/fml/macros.h"
|
||||
#include "flutter/fml/unique_fd.h"
|
||||
|
||||
#ifdef ERROR
|
||||
#undef ERROR
|
||||
#endif
|
||||
|
||||
namespace fml {
|
||||
|
||||
enum class OpenPermission {
|
||||
kRead = 1,
|
||||
kWrite = 1 << 1,
|
||||
kReadWrite = kRead | kWrite,
|
||||
kExecute,
|
||||
class Mapping;
|
||||
|
||||
enum class FilePermission {
|
||||
kRead,
|
||||
kWrite,
|
||||
kReadWrite,
|
||||
};
|
||||
|
||||
std::string CreateTemporaryDirectory();
|
||||
|
||||
fml::UniqueFD OpenFile(const char* path,
|
||||
OpenPermission permission,
|
||||
bool is_directory = false);
|
||||
bool create_if_necessary,
|
||||
FilePermission permission);
|
||||
|
||||
fml::UniqueFD OpenFile(const fml::UniqueFD& base_directory,
|
||||
const char* path,
|
||||
OpenPermission permission,
|
||||
bool is_directory = false);
|
||||
bool create_if_necessary,
|
||||
FilePermission permission);
|
||||
|
||||
fml::UniqueFD OpenDirectory(const char* path,
|
||||
bool create_if_necessary,
|
||||
FilePermission permission);
|
||||
|
||||
fml::UniqueFD OpenDirectory(const fml::UniqueFD& base_directory,
|
||||
const char* path,
|
||||
bool create_if_necessary,
|
||||
FilePermission permission);
|
||||
|
||||
fml::UniqueFD Duplicate(fml::UniqueFD::element_type descriptor);
|
||||
|
||||
@@ -33,6 +53,50 @@ bool IsDirectory(const fml::UniqueFD& directory);
|
||||
// Returns whether the given path is a file.
|
||||
bool IsFile(const std::string& path);
|
||||
|
||||
bool TruncateFile(const fml::UniqueFD& file, size_t size);
|
||||
|
||||
bool FileExists(const fml::UniqueFD& base_directory, const char* path);
|
||||
|
||||
bool UnlinkDirectory(const char* path);
|
||||
|
||||
bool UnlinkDirectory(const fml::UniqueFD& base_directory, const char* path);
|
||||
|
||||
bool UnlinkFile(const char* path);
|
||||
|
||||
bool UnlinkFile(const fml::UniqueFD& base_directory, const char* path);
|
||||
|
||||
fml::UniqueFD CreateDirectory(const fml::UniqueFD& base_directory,
|
||||
const std::vector<std::string>& components,
|
||||
FilePermission permission);
|
||||
|
||||
bool WriteAtomically(const fml::UniqueFD& base_directory,
|
||||
const char* file_name,
|
||||
const Mapping& mapping);
|
||||
|
||||
class ScopedTemporaryDirectory {
|
||||
public:
|
||||
ScopedTemporaryDirectory() {
|
||||
path_ = CreateTemporaryDirectory();
|
||||
if (path_ != "") {
|
||||
dir_fd_ = OpenDirectory(path_.c_str(), false, FilePermission::kRead);
|
||||
}
|
||||
}
|
||||
|
||||
~ScopedTemporaryDirectory() {
|
||||
if (path_ != "") {
|
||||
if (!UnlinkDirectory(path_.c_str())) {
|
||||
FML_LOG(ERROR) << "Could not remove directory: " << path_;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const UniqueFD& fd() { return dir_fd_; }
|
||||
|
||||
private:
|
||||
std::string path_;
|
||||
UniqueFD dir_fd_;
|
||||
};
|
||||
|
||||
} // namespace fml
|
||||
|
||||
#endif // FLUTTER_FML_FILE_H_
|
||||
|
||||
157
engine/src/flutter/fml/file_unittest.cc
Normal file
157
engine/src/flutter/fml/file_unittest.cc
Normal file
@@ -0,0 +1,157 @@
|
||||
// Copyright 2018 The Flutter 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 <memory>
|
||||
#include <vector>
|
||||
|
||||
#include "gtest/gtest.h"
|
||||
|
||||
#include "flutter/fml/build_config.h"
|
||||
#include "flutter/fml/file.h"
|
||||
#include "flutter/fml/mapping.h"
|
||||
|
||||
static bool WriteStringToFile(const fml::UniqueFD& fd,
|
||||
const std::string& contents) {
|
||||
if (!fml::TruncateFile(fd, contents.size())) {
|
||||
return false;
|
||||
}
|
||||
|
||||
fml::FileMapping mapping(fd, {fml::FileMapping::Protection::kWrite});
|
||||
if (mapping.GetSize() != contents.size()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (mapping.GetMutableMapping() == nullptr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
::memmove(mapping.GetMutableMapping(), contents.data(), contents.size());
|
||||
return true;
|
||||
}
|
||||
|
||||
static std::string ReadStringFromFile(const fml::UniqueFD& fd) {
|
||||
fml::FileMapping mapping(fd);
|
||||
|
||||
if (mapping.GetMapping() == nullptr) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return {reinterpret_cast<const char*>(mapping.GetMapping()),
|
||||
mapping.GetSize()};
|
||||
}
|
||||
|
||||
TEST(FileTest, CreateTemporaryAndUnlink) {
|
||||
auto dir_name = fml::CreateTemporaryDirectory();
|
||||
ASSERT_NE(dir_name, "");
|
||||
auto dir =
|
||||
fml::OpenDirectory(dir_name.c_str(), false, fml::FilePermission::kRead);
|
||||
ASSERT_TRUE(dir.is_valid());
|
||||
dir.reset();
|
||||
ASSERT_TRUE(fml::UnlinkDirectory(dir_name.c_str()));
|
||||
}
|
||||
|
||||
TEST(FileTest, ScopedTempDirIsValid) {
|
||||
fml::ScopedTemporaryDirectory dir;
|
||||
ASSERT_TRUE(dir.fd().is_valid());
|
||||
}
|
||||
|
||||
TEST(FileTest, CanOpenFileForWriting) {
|
||||
fml::ScopedTemporaryDirectory dir;
|
||||
ASSERT_TRUE(dir.fd().is_valid());
|
||||
|
||||
auto fd =
|
||||
fml::OpenFile(dir.fd(), "some.txt", true, fml::FilePermission::kWrite);
|
||||
ASSERT_TRUE(fd.is_valid());
|
||||
fd.reset();
|
||||
ASSERT_TRUE(fml::UnlinkFile(dir.fd(), "some.txt"));
|
||||
}
|
||||
|
||||
TEST(FileTest, CanTruncateAndWrite) {
|
||||
fml::ScopedTemporaryDirectory dir;
|
||||
ASSERT_TRUE(dir.fd().is_valid());
|
||||
|
||||
std::string contents = "some contents here";
|
||||
|
||||
{
|
||||
auto fd = fml::OpenFile(dir.fd(), "some.txt", true,
|
||||
fml::FilePermission::kReadWrite);
|
||||
ASSERT_TRUE(fd.is_valid());
|
||||
|
||||
ASSERT_TRUE(fml::TruncateFile(fd, contents.size()));
|
||||
|
||||
fml::FileMapping mapping(fd, {fml::FileMapping::Protection::kWrite});
|
||||
ASSERT_EQ(mapping.GetSize(), contents.size());
|
||||
ASSERT_NE(mapping.GetMutableMapping(), nullptr);
|
||||
|
||||
::memcpy(mapping.GetMutableMapping(), contents.data(), contents.size());
|
||||
}
|
||||
|
||||
{
|
||||
auto fd =
|
||||
fml::OpenFile(dir.fd(), "some.txt", false, fml::FilePermission::kRead);
|
||||
ASSERT_TRUE(fd.is_valid());
|
||||
|
||||
fml::FileMapping mapping(fd);
|
||||
ASSERT_EQ(mapping.GetSize(), contents.size());
|
||||
|
||||
ASSERT_EQ(0,
|
||||
::memcmp(mapping.GetMapping(), contents.data(), contents.size()));
|
||||
}
|
||||
|
||||
fml::UnlinkFile(dir.fd(), "some.txt");
|
||||
}
|
||||
|
||||
TEST(FileTest, CreateDirectoryStructure) {
|
||||
fml::ScopedTemporaryDirectory dir;
|
||||
|
||||
std::string contents = "These are my contents";
|
||||
{
|
||||
auto sub = fml::CreateDirectory(dir.fd(), {"a", "b", "c"},
|
||||
fml::FilePermission::kReadWrite);
|
||||
ASSERT_TRUE(sub.is_valid());
|
||||
auto file = fml::OpenFile(sub, "my_contents", true,
|
||||
fml::FilePermission::kReadWrite);
|
||||
ASSERT_TRUE(file.is_valid());
|
||||
ASSERT_TRUE(WriteStringToFile(file, contents));
|
||||
}
|
||||
|
||||
const char* file_path = "a/b/c/my_contents";
|
||||
|
||||
{
|
||||
auto contents_file =
|
||||
fml::OpenFile(dir.fd(), file_path, false, fml::FilePermission::kRead);
|
||||
ASSERT_EQ(ReadStringFromFile(contents_file), contents);
|
||||
}
|
||||
|
||||
// Cleanup.
|
||||
ASSERT_TRUE(fml::UnlinkFile(dir.fd(), file_path));
|
||||
ASSERT_TRUE(fml::UnlinkDirectory(dir.fd(), "a/b/c"));
|
||||
ASSERT_TRUE(fml::UnlinkDirectory(dir.fd(), "a/b"));
|
||||
ASSERT_TRUE(fml::UnlinkDirectory(dir.fd(), "a"));
|
||||
}
|
||||
|
||||
#if OS_WIN
|
||||
#define AtomicWriteTest DISABLED_AtomicWriteTest
|
||||
#else
|
||||
#define AtomicWriteTest AtomicWriteTest
|
||||
#endif
|
||||
TEST(FileTest, AtomicWriteTest) {
|
||||
fml::ScopedTemporaryDirectory dir;
|
||||
|
||||
const std::string contents = "These are my contents.";
|
||||
|
||||
auto data = std::make_unique<fml::DataMapping>(
|
||||
std::vector<uint8_t>{contents.begin(), contents.end()});
|
||||
|
||||
// Write.
|
||||
ASSERT_TRUE(fml::WriteAtomically(dir.fd(), "precious_data", *data));
|
||||
|
||||
// Read and verify.
|
||||
ASSERT_EQ(contents,
|
||||
ReadStringFromFile(fml::OpenFile(dir.fd(), "precious_data", false,
|
||||
fml::FilePermission::kRead)));
|
||||
|
||||
// Cleanup.
|
||||
ASSERT_TRUE(fml::UnlinkFile(dir.fd(), "precious_data"));
|
||||
}
|
||||
@@ -16,12 +16,6 @@
|
||||
namespace fml {
|
||||
namespace icu {
|
||||
|
||||
#if OS_WIN
|
||||
static constexpr char kPathSeparator = '\\';
|
||||
#else
|
||||
static constexpr char kPathSeparator = '/';
|
||||
#endif
|
||||
|
||||
class ICUContext {
|
||||
public:
|
||||
ICUContext(const std::string& icu_data_path) : valid_(false) {
|
||||
@@ -31,25 +25,37 @@ class ICUContext {
|
||||
~ICUContext() = default;
|
||||
|
||||
bool SetupMapping(const std::string& icu_data_path) {
|
||||
// Check if the explicit path specified exists.
|
||||
auto path_mapping = std::make_unique<FileMapping>(icu_data_path, false);
|
||||
if (path_mapping->GetSize() != 0) {
|
||||
mapping_ = std::move(path_mapping);
|
||||
return true;
|
||||
// Check if the path exists and it readable directly.
|
||||
auto fd =
|
||||
fml::OpenFile(icu_data_path.c_str(), false, fml::FilePermission::kRead);
|
||||
|
||||
// Check the path relative to the current executable.
|
||||
if (!fd.is_valid()) {
|
||||
auto directory = fml::paths::GetExecutableDirectoryPath();
|
||||
|
||||
if (!directory.first) {
|
||||
return false;
|
||||
}
|
||||
|
||||
std::string path_relative_to_executable =
|
||||
paths::JoinPaths({directory.second, icu_data_path});
|
||||
|
||||
fd = fml::OpenFile(path_relative_to_executable.c_str(), false,
|
||||
fml::FilePermission::kRead);
|
||||
}
|
||||
|
||||
// Check if the mapping can by directly accessed via a file path. In this
|
||||
// case, the data file needs to be next to the executable.
|
||||
auto directory = fml::paths::GetExecutableDirectoryPath();
|
||||
|
||||
if (!directory.first) {
|
||||
if (!fd.is_valid()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
auto file = std::make_unique<FileMapping>(
|
||||
directory.second + kPathSeparator + icu_data_path, false);
|
||||
if (file->GetSize() != 0) {
|
||||
mapping_ = std::move(file);
|
||||
std::initializer_list<FileMapping::Protection> protection = {
|
||||
fml::FileMapping::Protection::kRead};
|
||||
|
||||
auto file_mapping =
|
||||
std::make_unique<FileMapping>(fd, std::move(protection));
|
||||
|
||||
if (file_mapping->GetSize() != 0) {
|
||||
mapping_ = std::move(file_mapping);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -6,6 +6,10 @@
|
||||
|
||||
namespace fml {
|
||||
|
||||
uint8_t* FileMapping::GetMutableMapping() {
|
||||
return mutable_mapping_;
|
||||
}
|
||||
|
||||
DataMapping::DataMapping(std::vector<uint8_t> data) : data_(std::move(data)) {}
|
||||
|
||||
DataMapping::~DataMapping() = default;
|
||||
@@ -17,4 +21,5 @@ size_t DataMapping::GetSize() const {
|
||||
const uint8_t* DataMapping::GetMapping() const {
|
||||
return data_.data();
|
||||
}
|
||||
|
||||
} // namespace fml
|
||||
|
||||
@@ -5,11 +5,13 @@
|
||||
#ifndef FLUTTER_FML_MAPPING_H_
|
||||
#define FLUTTER_FML_MAPPING_H_
|
||||
|
||||
#include <initializer_list>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "flutter/fml/build_config.h"
|
||||
#include "flutter/fml/file.h"
|
||||
#include "flutter/fml/macros.h"
|
||||
#include "flutter/fml/unique_fd.h"
|
||||
|
||||
@@ -31,9 +33,15 @@ class Mapping {
|
||||
|
||||
class FileMapping : public Mapping {
|
||||
public:
|
||||
FileMapping(const std::string& path, bool executable = false);
|
||||
enum class Protection {
|
||||
kRead,
|
||||
kWrite,
|
||||
kExecute,
|
||||
};
|
||||
|
||||
FileMapping(const fml::UniqueFD& fd, bool executable = false);
|
||||
FileMapping(const fml::UniqueFD& fd,
|
||||
std::initializer_list<Protection> protection = {
|
||||
Protection::kRead});
|
||||
|
||||
~FileMapping() override;
|
||||
|
||||
@@ -41,9 +49,12 @@ class FileMapping : public Mapping {
|
||||
|
||||
const uint8_t* GetMapping() const override;
|
||||
|
||||
uint8_t* GetMutableMapping();
|
||||
|
||||
private:
|
||||
size_t size_ = 0;
|
||||
uint8_t* mapping_ = nullptr;
|
||||
uint8_t* mutable_mapping_ = nullptr;
|
||||
|
||||
#if OS_WIN
|
||||
fml::UniqueFD mapping_handle_;
|
||||
@@ -68,6 +79,22 @@ class DataMapping : public Mapping {
|
||||
FML_DISALLOW_COPY_AND_ASSIGN(DataMapping);
|
||||
};
|
||||
|
||||
class NonOwnedMapping : public Mapping {
|
||||
public:
|
||||
NonOwnedMapping(const uint8_t* data, size_t size)
|
||||
: data_(data), size_(size) {}
|
||||
|
||||
size_t GetSize() const override { return size_; }
|
||||
|
||||
const uint8_t* GetMapping() const override { return data_; }
|
||||
|
||||
private:
|
||||
const uint8_t* const data_;
|
||||
const size_t size_;
|
||||
|
||||
FML_DISALLOW_COPY_AND_ASSIGN(NonOwnedMapping);
|
||||
};
|
||||
|
||||
} // namespace fml
|
||||
|
||||
#endif // FLUTTER_FML_MAPPING_H_
|
||||
|
||||
@@ -8,11 +8,16 @@
|
||||
#include <string>
|
||||
#include <utility>
|
||||
|
||||
#include "flutter/fml/unique_fd.h"
|
||||
|
||||
namespace fml {
|
||||
namespace paths {
|
||||
|
||||
std::pair<bool, std::string> GetExecutableDirectoryPath();
|
||||
|
||||
// Get the directory to the application's caches directory.
|
||||
fml::UniqueFD GetCachesDirectory();
|
||||
|
||||
std::string JoinPaths(std::initializer_list<std::string> components);
|
||||
|
||||
// Returns the absolute path of a possibly relative path.
|
||||
|
||||
@@ -2,7 +2,9 @@
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include "flutter/fml/paths.h"
|
||||
#include "flutter/fml/platform/android/paths_android.h"
|
||||
|
||||
#include "flutter/fml/file.h"
|
||||
|
||||
namespace fml {
|
||||
namespace paths {
|
||||
@@ -11,5 +13,17 @@ std::pair<bool, std::string> GetExecutableDirectoryPath() {
|
||||
return {false, ""};
|
||||
}
|
||||
|
||||
static std::string gCachesPath;
|
||||
|
||||
void InitializeAndroidCachesPath(std::string caches_path) {
|
||||
gCachesPath = std::move(caches_path);
|
||||
}
|
||||
|
||||
fml::UniqueFD GetCachesDirectory() {
|
||||
// If the caches path is not initialized, the FD will be invalid and caching
|
||||
// will be disabled throughout the system.
|
||||
return OpenDirectory(gCachesPath.c_str(), false, fml::FilePermission::kRead);
|
||||
}
|
||||
|
||||
} // namespace paths
|
||||
} // namespace fml
|
||||
|
||||
19
engine/src/flutter/fml/platform/android/paths_android.h
Normal file
19
engine/src/flutter/fml/platform/android/paths_android.h
Normal file
@@ -0,0 +1,19 @@
|
||||
// Copyright 2018 The Flutter Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#ifndef FLUTTER_FML_PLATFORM_ANDROID_PATHS_ANDROID_H_
|
||||
#define FLUTTER_FML_PLATFORM_ANDROID_PATHS_ANDROID_H_
|
||||
|
||||
#include "flutter/fml/macros.h"
|
||||
#include "flutter/fml/paths.h"
|
||||
|
||||
namespace fml {
|
||||
namespace paths {
|
||||
|
||||
void InitializeAndroidCachesPath(std::string caches_path);
|
||||
|
||||
} // namespace paths
|
||||
} // namespace fml
|
||||
|
||||
#endif // FLUTTER_FML_PLATFORM_ANDROID_PATHS_ANDROID_H_
|
||||
@@ -6,11 +6,27 @@
|
||||
|
||||
#include <Foundation/Foundation.h>
|
||||
|
||||
#include "flutter/fml/file.h"
|
||||
|
||||
namespace fml {
|
||||
namespace paths {
|
||||
|
||||
std::pair<bool, std::string> GetExecutableDirectoryPath() {
|
||||
return {true, GetDirectoryName([NSBundle mainBundle].executablePath.UTF8String)};
|
||||
@autoreleasepool {
|
||||
return {true, GetDirectoryName([NSBundle mainBundle].executablePath.UTF8String)};
|
||||
}
|
||||
}
|
||||
|
||||
fml::UniqueFD GetCachesDirectory() {
|
||||
@autoreleasepool {
|
||||
auto items = [[NSFileManager defaultManager] URLsForDirectory:NSCachesDirectory
|
||||
inDomains:NSUserDomainMask];
|
||||
if (items.count == 0) {
|
||||
return {};
|
||||
}
|
||||
|
||||
return OpenDirectory(items[0].fileSystemRepresentation, false, FilePermission::kRead);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace paths
|
||||
|
||||
@@ -11,5 +11,10 @@ std::pair<bool, std::string> GetExecutableDirectoryPath() {
|
||||
return {false, ""};
|
||||
}
|
||||
|
||||
fml::UniqueFD GetCachesDirectory() {
|
||||
// Unsupported on this platform.
|
||||
return {};
|
||||
}
|
||||
|
||||
} // namespace paths
|
||||
} // namespace fml
|
||||
|
||||
@@ -22,5 +22,10 @@ std::pair<bool, std::string> GetExecutableDirectoryPath() {
|
||||
std::string{path, static_cast<size_t>(read_size)})};
|
||||
}
|
||||
|
||||
fml::UniqueFD GetCachesDirectory() {
|
||||
// Unsupported on this platform.
|
||||
return {};
|
||||
}
|
||||
|
||||
} // namespace paths
|
||||
} // namespace fml
|
||||
|
||||
@@ -5,49 +5,113 @@
|
||||
#include "flutter/fml/file.h"
|
||||
|
||||
#include <fcntl.h>
|
||||
#include <sys/mman.h>
|
||||
#include <sys/stat.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <memory>
|
||||
#include <sstream>
|
||||
|
||||
#include "flutter/fml/eintr_wrapper.h"
|
||||
#include "flutter/fml/mapping.h"
|
||||
|
||||
namespace fml {
|
||||
|
||||
std::string CreateTemporaryDirectory() {
|
||||
char directory_name[] = "/tmp/flutter_XXXXXXXX";
|
||||
auto result = ::mkdtemp(directory_name);
|
||||
if (result == nullptr) {
|
||||
return "";
|
||||
}
|
||||
return {result};
|
||||
}
|
||||
|
||||
static int ToPosixAccessFlags(FilePermission permission) {
|
||||
int flags = 0;
|
||||
switch (permission) {
|
||||
case FilePermission::kRead:
|
||||
flags |= O_RDONLY; // read only
|
||||
break;
|
||||
case FilePermission::kWrite:
|
||||
flags |= O_WRONLY; // write only
|
||||
break;
|
||||
case FilePermission::kReadWrite:
|
||||
flags |= O_RDWR; // read-write
|
||||
break;
|
||||
}
|
||||
return flags;
|
||||
}
|
||||
|
||||
static int ToPosixCreateModeFlags(FilePermission permission) {
|
||||
int mode = 0;
|
||||
switch (permission) {
|
||||
case FilePermission::kRead:
|
||||
mode |= S_IRUSR;
|
||||
break;
|
||||
case FilePermission::kWrite:
|
||||
mode |= S_IWUSR;
|
||||
break;
|
||||
case FilePermission::kReadWrite:
|
||||
mode |= S_IRUSR | S_IWUSR;
|
||||
break;
|
||||
}
|
||||
return mode;
|
||||
}
|
||||
|
||||
fml::UniqueFD OpenFile(const char* path,
|
||||
OpenPermission permission,
|
||||
bool is_directory) {
|
||||
return OpenFile(fml::UniqueFD{AT_FDCWD}, path, permission, is_directory);
|
||||
bool create_if_necessary,
|
||||
FilePermission permission) {
|
||||
return OpenFile(fml::UniqueFD{AT_FDCWD}, path, create_if_necessary,
|
||||
permission);
|
||||
}
|
||||
|
||||
fml::UniqueFD OpenFile(const fml::UniqueFD& base_directory,
|
||||
const char* path,
|
||||
OpenPermission permission,
|
||||
bool is_directory) {
|
||||
bool create_if_necessary,
|
||||
FilePermission permission) {
|
||||
if (path == nullptr) {
|
||||
return fml::UniqueFD{};
|
||||
return {};
|
||||
}
|
||||
|
||||
int flags = 0;
|
||||
switch (permission) {
|
||||
case OpenPermission::kRead:
|
||||
flags = O_RDONLY;
|
||||
break;
|
||||
case OpenPermission::kWrite:
|
||||
flags = O_WRONLY;
|
||||
break;
|
||||
case OpenPermission::kReadWrite:
|
||||
flags = O_RDWR;
|
||||
break;
|
||||
case OpenPermission::kExecute:
|
||||
flags = O_RDONLY;
|
||||
break;
|
||||
}
|
||||
int mode = 0;
|
||||
|
||||
if (is_directory) {
|
||||
flags |= O_DIRECTORY;
|
||||
if (create_if_necessary && !FileExists(base_directory, path)) {
|
||||
flags = ToPosixAccessFlags(permission) | O_CREAT | O_TRUNC;
|
||||
mode = ToPosixCreateModeFlags(permission);
|
||||
} else {
|
||||
flags = ToPosixAccessFlags(permission);
|
||||
mode = 0; // Not creating since it already exists.
|
||||
}
|
||||
|
||||
return fml::UniqueFD{
|
||||
FML_HANDLE_EINTR(::openat(base_directory.get(), path, flags))};
|
||||
FML_HANDLE_EINTR(::openat(base_directory.get(), path, flags, mode))};
|
||||
}
|
||||
|
||||
fml::UniqueFD OpenDirectory(const char* path,
|
||||
bool create_if_necessary,
|
||||
FilePermission permission) {
|
||||
return OpenDirectory(fml::UniqueFD{AT_FDCWD}, path, create_if_necessary,
|
||||
permission);
|
||||
}
|
||||
|
||||
fml::UniqueFD OpenDirectory(const fml::UniqueFD& base_directory,
|
||||
const char* path,
|
||||
bool create_if_necessary,
|
||||
FilePermission permission) {
|
||||
if (path == nullptr) {
|
||||
return {};
|
||||
}
|
||||
|
||||
if (create_if_necessary && !FileExists(base_directory, path)) {
|
||||
if (::mkdirat(base_directory.get(), path,
|
||||
ToPosixCreateModeFlags(permission) | S_IXUSR) != 0) {
|
||||
return {};
|
||||
}
|
||||
}
|
||||
|
||||
return fml::UniqueFD{FML_HANDLE_EINTR(
|
||||
::openat(base_directory.get(), path, O_RDONLY | O_DIRECTORY))};
|
||||
}
|
||||
|
||||
fml::UniqueFD Duplicate(fml::UniqueFD::element_type descriptor) {
|
||||
@@ -70,9 +134,80 @@ bool IsDirectory(const fml::UniqueFD& directory) {
|
||||
|
||||
bool IsFile(const std::string& path) {
|
||||
struct stat buf;
|
||||
if (stat(path.c_str(), &buf) != 0)
|
||||
if (stat(path.c_str(), &buf) != 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return S_ISREG(buf.st_mode);
|
||||
}
|
||||
|
||||
bool TruncateFile(const fml::UniqueFD& file, size_t size) {
|
||||
if (!file.is_valid()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return ::ftruncate(file.get(), size) == 0;
|
||||
}
|
||||
|
||||
bool UnlinkDirectory(const char* path) {
|
||||
return UnlinkDirectory(fml::UniqueFD{AT_FDCWD}, path);
|
||||
}
|
||||
|
||||
bool UnlinkDirectory(const fml::UniqueFD& base_directory, const char* path) {
|
||||
return ::unlinkat(base_directory.get(), path, AT_REMOVEDIR) == 0;
|
||||
}
|
||||
|
||||
bool UnlinkFile(const char* path) {
|
||||
return UnlinkFile(fml::UniqueFD{AT_FDCWD}, path);
|
||||
}
|
||||
|
||||
bool UnlinkFile(const fml::UniqueFD& base_directory, const char* path) {
|
||||
return ::unlinkat(base_directory.get(), path, 0) == 0;
|
||||
}
|
||||
|
||||
bool FileExists(const fml::UniqueFD& base_directory, const char* path) {
|
||||
if (!base_directory.is_valid()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return ::faccessat(base_directory.get(), path, F_OK, 0) == 0;
|
||||
}
|
||||
|
||||
bool WriteAtomically(const fml::UniqueFD& base_directory,
|
||||
const char* file_name,
|
||||
const Mapping& data) {
|
||||
if (file_name == nullptr || data.GetMapping() == nullptr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
std::stringstream stream;
|
||||
stream << file_name << ".temp";
|
||||
const auto temp_file_name = stream.str();
|
||||
|
||||
auto temp_file = OpenFile(base_directory, temp_file_name.c_str(), true,
|
||||
FilePermission::kReadWrite);
|
||||
if (!temp_file.is_valid()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!TruncateFile(temp_file, data.GetSize())) {
|
||||
return false;
|
||||
}
|
||||
|
||||
FileMapping mapping(temp_file, {FileMapping::Protection::kWrite});
|
||||
if (mapping.GetMutableMapping() == nullptr ||
|
||||
data.GetSize() != mapping.GetSize()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
::memcpy(mapping.GetMutableMapping(), data.GetMapping(), data.GetSize());
|
||||
|
||||
if (::msync(mapping.GetMutableMapping(), data.GetSize(), MS_SYNC) != 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return ::renameat(base_directory.get(), temp_file_name.c_str(),
|
||||
base_directory.get(), file_name) == 0;
|
||||
}
|
||||
|
||||
} // namespace fml
|
||||
|
||||
@@ -17,16 +17,41 @@
|
||||
|
||||
namespace fml {
|
||||
|
||||
static int ToPosixProtectionFlags(
|
||||
std::initializer_list<FileMapping::Protection> protection_flags) {
|
||||
int flags = 0;
|
||||
for (auto protection : protection_flags) {
|
||||
switch (protection) {
|
||||
case FileMapping::Protection::kRead:
|
||||
flags |= PROT_READ;
|
||||
break;
|
||||
case FileMapping::Protection::kWrite:
|
||||
flags |= PROT_WRITE;
|
||||
break;
|
||||
case FileMapping::Protection::kExecute:
|
||||
flags |= PROT_READ | PROT_EXEC;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return flags;
|
||||
}
|
||||
|
||||
static bool IsWritable(
|
||||
std::initializer_list<FileMapping::Protection> protection_flags) {
|
||||
for (auto protection : protection_flags) {
|
||||
if (protection == FileMapping::Protection::kWrite) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
Mapping::Mapping() = default;
|
||||
|
||||
Mapping::~Mapping() = default;
|
||||
|
||||
FileMapping::FileMapping(const std::string& path, bool executable)
|
||||
: FileMapping(
|
||||
fml::UniqueFD{FML_HANDLE_EINTR(::open(path.c_str(), O_RDONLY))},
|
||||
executable) {}
|
||||
|
||||
FileMapping::FileMapping(const fml::UniqueFD& handle, bool executable)
|
||||
FileMapping::FileMapping(const fml::UniqueFD& handle,
|
||||
std::initializer_list<Protection> protection)
|
||||
: size_(0), mapping_(nullptr) {
|
||||
if (!handle.is_valid()) {
|
||||
return;
|
||||
@@ -42,13 +67,11 @@ FileMapping::FileMapping(const fml::UniqueFD& handle, bool executable)
|
||||
return;
|
||||
}
|
||||
|
||||
int flags = PROT_READ;
|
||||
if (executable) {
|
||||
flags |= PROT_EXEC;
|
||||
}
|
||||
const auto is_writable = IsWritable(protection);
|
||||
|
||||
auto mapping =
|
||||
::mmap(nullptr, stat_buffer.st_size, flags, MAP_PRIVATE, handle.get(), 0);
|
||||
::mmap(nullptr, stat_buffer.st_size, ToPosixProtectionFlags(protection),
|
||||
is_writable ? MAP_SHARED : MAP_PRIVATE, handle.get(), 0);
|
||||
|
||||
if (mapping == MAP_FAILED) {
|
||||
return;
|
||||
@@ -56,6 +79,9 @@ FileMapping::FileMapping(const fml::UniqueFD& handle, bool executable)
|
||||
|
||||
mapping_ = static_cast<uint8_t*>(mapping);
|
||||
size_ = stat_buffer.st_size;
|
||||
if (is_writable) {
|
||||
mutable_mapping_ = mapping_;
|
||||
}
|
||||
}
|
||||
|
||||
FileMapping::~FileMapping() {
|
||||
|
||||
46
engine/src/flutter/fml/platform/win/errors_win.cc
Normal file
46
engine/src/flutter/fml/platform/win/errors_win.cc
Normal file
@@ -0,0 +1,46 @@
|
||||
// Copyright 2018 The Flutter 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 "flutter/fml/platform/win/errors_win.h"
|
||||
|
||||
#include <Windows.h>
|
||||
|
||||
#include <sstream>
|
||||
|
||||
#include "flutter/fml/platform/win/wstring_conversion.h"
|
||||
|
||||
namespace fml {
|
||||
|
||||
std::string GetLastErrorMessage() {
|
||||
DWORD last_error = ::GetLastError();
|
||||
if (last_error == 0) {
|
||||
return {};
|
||||
}
|
||||
|
||||
const DWORD flags = FORMAT_MESSAGE_ALLOCATE_BUFFER |
|
||||
FORMAT_MESSAGE_FROM_SYSTEM |
|
||||
FORMAT_MESSAGE_IGNORE_INSERTS;
|
||||
|
||||
wchar_t* buffer = nullptr;
|
||||
size_t size = ::FormatMessage(
|
||||
flags, // dwFlags
|
||||
NULL, // lpSource
|
||||
last_error, // dwMessageId
|
||||
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // dwLanguageId
|
||||
(LPWSTR)&buffer, // lpBuffer
|
||||
0, // nSize
|
||||
NULL // Arguments
|
||||
);
|
||||
|
||||
std::wstring message(buffer, size);
|
||||
|
||||
::LocalFree(buffer);
|
||||
|
||||
std::wstringstream stream;
|
||||
stream << message << " (" << last_error << ").";
|
||||
|
||||
return WideStringToString(stream.str());
|
||||
}
|
||||
|
||||
} // namespace fml
|
||||
16
engine/src/flutter/fml/platform/win/errors_win.h
Normal file
16
engine/src/flutter/fml/platform/win/errors_win.h
Normal file
@@ -0,0 +1,16 @@
|
||||
// Copyright 2018 The Flutter Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#ifndef FLUTTER_FML_PLATFORM_WIN_ERRORS_WIN_H_
|
||||
#define FLUTTER_FML_PLATFORM_WIN_ERRORS_WIN_H_
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace fml {
|
||||
|
||||
std::string GetLastErrorMessage();
|
||||
|
||||
} // namespace fml
|
||||
|
||||
#endif // FLUTTER_FML_PLATFORM_WIN_ERRORS_WIN_H_
|
||||
@@ -4,6 +4,7 @@
|
||||
|
||||
#include "flutter/fml/file.h"
|
||||
|
||||
#include <Fileapi.h>
|
||||
#include <Shlwapi.h>
|
||||
#include <fcntl.h>
|
||||
#include <limits.h>
|
||||
@@ -13,6 +14,8 @@
|
||||
#include <sstream>
|
||||
|
||||
#include "flutter/fml/build_config.h"
|
||||
#include "flutter/fml/mapping.h"
|
||||
#include "flutter/fml/platform/win/errors_win.h"
|
||||
#include "flutter/fml/platform/win/wstring_conversion.h"
|
||||
|
||||
#if defined(OS_WIN)
|
||||
@@ -21,85 +24,200 @@
|
||||
|
||||
namespace fml {
|
||||
|
||||
static fml::UniqueFD OpenFile(std::wstring path,
|
||||
OpenPermission permission,
|
||||
bool is_directory) {
|
||||
if (path.size() == 0) {
|
||||
return fml::UniqueFD{};
|
||||
}
|
||||
|
||||
DWORD desired_access = 0;
|
||||
|
||||
switch (permission) {
|
||||
case OpenPermission::kRead:
|
||||
desired_access = GENERIC_READ;
|
||||
break;
|
||||
case OpenPermission::kWrite:
|
||||
desired_access = GENERIC_WRITE;
|
||||
break;
|
||||
case OpenPermission::kReadWrite:
|
||||
desired_access = GENERIC_WRITE | GENERIC_READ;
|
||||
break;
|
||||
case OpenPermission::kExecute:
|
||||
desired_access = GENERIC_READ | GENERIC_EXECUTE;
|
||||
break;
|
||||
}
|
||||
|
||||
DWORD flags = FILE_ATTRIBUTE_NORMAL;
|
||||
|
||||
if (is_directory) {
|
||||
flags |= FILE_FLAG_BACKUP_SEMANTICS;
|
||||
static std::string GetFullHandlePath(const fml::UniqueFD& handle) {
|
||||
wchar_t buffer[MAX_PATH] = {0};
|
||||
const DWORD buffer_size = ::GetFinalPathNameByHandle(
|
||||
handle.get(), buffer, MAX_PATH, FILE_NAME_NORMALIZED);
|
||||
if (buffer_size == 0) {
|
||||
FML_DLOG(ERROR) << "Could not get file handle path. "
|
||||
<< GetLastErrorMessage();
|
||||
return {};
|
||||
}
|
||||
return WideStringToString({buffer, buffer_size});
|
||||
}
|
||||
|
||||
static std::string GetAbsolutePath(const fml::UniqueFD& base_directory,
|
||||
const char* subpath) {
|
||||
std::stringstream stream;
|
||||
stream << GetFullHandlePath(base_directory) << "\\" << subpath;
|
||||
auto path = stream.str();
|
||||
std::replace(path.begin(), path.end(), '/', '\\');
|
||||
|
||||
return fml::UniqueFD{::CreateFile(path.c_str(), // lpFileName
|
||||
desired_access, // dwDesiredAccess
|
||||
FILE_SHARE_READ, // dwShareMode
|
||||
0, // lpSecurityAttributes
|
||||
OPEN_EXISTING, // dwCreationDisposition
|
||||
flags, // dwFlagsAndAttributes
|
||||
0 // hTemplateFile
|
||||
)};
|
||||
return path;
|
||||
}
|
||||
|
||||
fml::UniqueFD OpenFile(const char* path,
|
||||
OpenPermission permission,
|
||||
bool is_directory) {
|
||||
return OpenFile(ConvertToWString(path), permission, is_directory);
|
||||
static std::wstring GetTemporaryDirectoryPath() {
|
||||
wchar_t wchar_path[MAX_PATH];
|
||||
auto result_size = ::GetTempPath(MAX_PATH, wchar_path);
|
||||
if (result_size > 0) {
|
||||
return {wchar_path, result_size};
|
||||
}
|
||||
FML_DLOG(ERROR) << "Could not get temporary directory path. "
|
||||
<< GetLastErrorMessage();
|
||||
return {};
|
||||
}
|
||||
|
||||
static std::wstring GetFullHandlePath(const fml::UniqueFD& handle) {
|
||||
wchar_t buffer[MAX_PATH];
|
||||
static DWORD GetDesiredAccessFlags(FilePermission permission) {
|
||||
switch (permission) {
|
||||
case FilePermission::kRead:
|
||||
return GENERIC_READ;
|
||||
case FilePermission::kWrite:
|
||||
return GENERIC_WRITE;
|
||||
case FilePermission::kReadWrite:
|
||||
return GENERIC_READ | GENERIC_WRITE;
|
||||
}
|
||||
return GENERIC_READ;
|
||||
}
|
||||
|
||||
DWORD returned = ::GetFinalPathNameByHandle(handle.get(), buffer, MAX_PATH,
|
||||
FILE_NAME_NORMALIZED);
|
||||
if (returned == 0 || returned > MAX_PATH) {
|
||||
static DWORD GetShareFlags(FilePermission permission) {
|
||||
switch (permission) {
|
||||
case FilePermission::kRead:
|
||||
return FILE_SHARE_READ;
|
||||
case FilePermission::kWrite:
|
||||
return FILE_SHARE_WRITE;
|
||||
case FilePermission::kReadWrite:
|
||||
return FILE_SHARE_READ | FILE_SHARE_WRITE;
|
||||
}
|
||||
return FILE_SHARE_READ;
|
||||
}
|
||||
|
||||
std::string CreateTemporaryDirectory() {
|
||||
// Get the system temporary directory.
|
||||
auto temp_dir_container = GetTemporaryDirectoryPath();
|
||||
if (temp_dir_container.size() == 0) {
|
||||
FML_DLOG(ERROR) << "Could not get system temporary directory.";
|
||||
return {};
|
||||
}
|
||||
|
||||
return {buffer};
|
||||
// Create a UUID.
|
||||
UUID uuid;
|
||||
RPC_STATUS status = UuidCreateSequential(&uuid);
|
||||
if (status != RPC_S_OK && status != RPC_S_UUID_LOCAL_ONLY) {
|
||||
FML_DLOG(ERROR) << "Could not create UUID";
|
||||
return {};
|
||||
}
|
||||
|
||||
RPC_WSTR uuid_string;
|
||||
status = UuidToString(&uuid, &uuid_string);
|
||||
if (status != RPC_S_OK) {
|
||||
FML_DLOG(ERROR) << "Could not create UUID to string.";
|
||||
return {};
|
||||
}
|
||||
|
||||
std::wstring uuid_str(reinterpret_cast<wchar_t*>(uuid_string));
|
||||
RpcStringFree(&uuid_string);
|
||||
|
||||
// Join the two and create a path to the new temporary directory.
|
||||
|
||||
std::wstringstream stream;
|
||||
stream << temp_dir_container << "\\" << uuid_str;
|
||||
auto temp_dir = stream.str();
|
||||
|
||||
auto dir_fd = OpenDirectory(WideStringToString(temp_dir).c_str(), true,
|
||||
FilePermission::kReadWrite);
|
||||
if (!dir_fd.is_valid()) {
|
||||
FML_DLOG(ERROR) << "Could not get temporary directory FD. "
|
||||
<< GetLastErrorMessage();
|
||||
return {};
|
||||
}
|
||||
|
||||
return WideStringToString(std::move(temp_dir));
|
||||
}
|
||||
|
||||
fml::UniqueFD OpenFile(const fml::UniqueFD& base_directory,
|
||||
const char* path,
|
||||
OpenPermission permission,
|
||||
bool is_directory) {
|
||||
// If the base directory is invalid or the path is absolute, use the generic
|
||||
// open file variant.
|
||||
if (!base_directory.is_valid()) {
|
||||
return OpenFile(path, permission, is_directory);
|
||||
bool create_if_necessary,
|
||||
FilePermission permission) {
|
||||
return OpenFile(GetAbsolutePath(base_directory, path).c_str(),
|
||||
create_if_necessary, permission);
|
||||
}
|
||||
|
||||
fml::UniqueFD OpenFile(const char* path,
|
||||
bool create_if_necessary,
|
||||
FilePermission permission) {
|
||||
if (path == nullptr || strlen(path) == 0) {
|
||||
return {};
|
||||
}
|
||||
|
||||
const auto wpath = ConvertToWString(path);
|
||||
auto file_name = StringToWideString({path});
|
||||
|
||||
if (!::PathIsRelative(wpath.c_str())) {
|
||||
return OpenFile(path, permission, is_directory);
|
||||
if (file_name.size() == 0) {
|
||||
return {};
|
||||
}
|
||||
|
||||
std::wstringstream stream;
|
||||
stream << GetFullHandlePath(base_directory) << "\\" << path;
|
||||
return OpenFile(stream.str(), permission, is_directory);
|
||||
const DWORD creation_disposition =
|
||||
create_if_necessary ? CREATE_NEW : OPEN_EXISTING;
|
||||
|
||||
const DWORD flags = FILE_ATTRIBUTE_NORMAL;
|
||||
|
||||
auto handle =
|
||||
CreateFile(file_name.c_str(), // lpFileName
|
||||
GetDesiredAccessFlags(permission), // dwDesiredAccess
|
||||
GetShareFlags(permission), // dwShareMode
|
||||
nullptr, // lpSecurityAttributes //
|
||||
creation_disposition, // dwCreationDisposition //
|
||||
flags, // dwFlagsAndAttributes //
|
||||
nullptr // hTemplateFile //
|
||||
);
|
||||
|
||||
if (handle == INVALID_HANDLE_VALUE) {
|
||||
FML_DLOG(ERROR) << "Could not open file. " << GetLastErrorMessage();
|
||||
return {};
|
||||
}
|
||||
|
||||
return fml::UniqueFD{handle};
|
||||
}
|
||||
|
||||
fml::UniqueFD OpenDirectory(const fml::UniqueFD& base_directory,
|
||||
const char* path,
|
||||
bool create_if_necessary,
|
||||
FilePermission permission) {
|
||||
return OpenDirectory(GetAbsolutePath(base_directory, path).c_str(),
|
||||
create_if_necessary, permission);
|
||||
}
|
||||
|
||||
fml::UniqueFD OpenDirectory(const char* path,
|
||||
bool create_if_necessary,
|
||||
FilePermission permission) {
|
||||
if (path == nullptr || strlen(path) == 0) {
|
||||
return {};
|
||||
}
|
||||
|
||||
auto file_name = StringToWideString({path});
|
||||
|
||||
if (file_name.size() == 0) {
|
||||
return {};
|
||||
}
|
||||
|
||||
if (create_if_necessary) {
|
||||
if (!::CreateDirectory(file_name.c_str(), nullptr)) {
|
||||
if (GetLastError() != ERROR_ALREADY_EXISTS) {
|
||||
FML_DLOG(ERROR) << "Could not create directory. "
|
||||
<< GetLastErrorMessage();
|
||||
return {};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const DWORD creation_disposition = OPEN_EXISTING;
|
||||
|
||||
const DWORD flags = FILE_ATTRIBUTE_NORMAL | FILE_FLAG_BACKUP_SEMANTICS;
|
||||
|
||||
auto handle =
|
||||
CreateFile(file_name.c_str(), // lpFileName
|
||||
GetDesiredAccessFlags(permission), // dwDesiredAccess
|
||||
GetShareFlags(permission), // dwShareMode
|
||||
nullptr, // lpSecurityAttributes //
|
||||
creation_disposition, // dwCreationDisposition //
|
||||
flags, // dwFlagsAndAttributes //
|
||||
nullptr // hTemplateFile //
|
||||
);
|
||||
|
||||
if (handle == INVALID_HANDLE_VALUE) {
|
||||
FML_DLOG(ERROR) << "Could not open file. " << GetLastErrorMessage();
|
||||
return {};
|
||||
}
|
||||
|
||||
return fml::UniqueFD{handle};
|
||||
}
|
||||
|
||||
fml::UniqueFD Duplicate(fml::UniqueFD::element_type descriptor) {
|
||||
@@ -127,6 +245,8 @@ fml::UniqueFD Duplicate(fml::UniqueFD::element_type descriptor) {
|
||||
bool IsDirectory(const fml::UniqueFD& directory) {
|
||||
BY_HANDLE_FILE_INFORMATION info;
|
||||
if (!::GetFileInformationByHandle(directory.get(), &info)) {
|
||||
FML_DLOG(ERROR) << "Could not get file information. "
|
||||
<< GetLastErrorMessage();
|
||||
return false;
|
||||
}
|
||||
return info.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY;
|
||||
@@ -139,4 +259,134 @@ bool IsFile(const std::string& path) {
|
||||
return S_ISREG(buf.st_mode);
|
||||
}
|
||||
|
||||
bool UnlinkDirectory(const char* path) {
|
||||
if (!::RemoveDirectory(ConvertToWString(path).c_str())) {
|
||||
FML_DLOG(ERROR) << "Could not remove directory: '" << path << "'. "
|
||||
<< GetLastErrorMessage();
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool UnlinkDirectory(const fml::UniqueFD& base_directory, const char* path) {
|
||||
if (!::RemoveDirectory(
|
||||
StringToWideString(GetAbsolutePath(base_directory, path)).c_str())) {
|
||||
FML_DLOG(ERROR) << "Could not remove directory: '" << path << "'. "
|
||||
<< GetLastErrorMessage();
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool UnlinkFile(const char* path) {
|
||||
if (!::DeleteFile(ConvertToWString(path).c_str())) {
|
||||
FML_DLOG(ERROR) << "Could not remove file: '" << path << "'. "
|
||||
<< GetLastErrorMessage();
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool UnlinkFile(const fml::UniqueFD& base_directory, const char* path) {
|
||||
if (!::DeleteFile(
|
||||
StringToWideString(GetAbsolutePath(base_directory, path)).c_str())) {
|
||||
FML_DLOG(ERROR) << "Could not remove file: '" << path << "'. "
|
||||
<< GetLastErrorMessage();
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool TruncateFile(const fml::UniqueFD& file, size_t size) {
|
||||
LARGE_INTEGER large_size;
|
||||
large_size.QuadPart = size;
|
||||
large_size.LowPart = SetFilePointer(file.get(), large_size.LowPart,
|
||||
&large_size.HighPart, FILE_BEGIN);
|
||||
if (large_size.LowPart == INVALID_SET_FILE_POINTER &&
|
||||
GetLastError() != NO_ERROR) {
|
||||
FML_DLOG(ERROR) << "Could not update file size. " << GetLastErrorMessage();
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!::SetEndOfFile(file.get())) {
|
||||
FML_DLOG(ERROR) << "Could not commit file size update. "
|
||||
<< GetLastErrorMessage();
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool WriteAtomically(const fml::UniqueFD& base_directory,
|
||||
const char* file_name,
|
||||
const Mapping& mapping) {
|
||||
if (file_name == nullptr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
auto file_path = GetAbsolutePath(base_directory, file_name);
|
||||
std::stringstream stream;
|
||||
stream << file_path << ".temp";
|
||||
auto temp_file_path = stream.str();
|
||||
|
||||
auto temp_file =
|
||||
OpenFile(temp_file_path.c_str(), true, FilePermission::kReadWrite);
|
||||
|
||||
if (!temp_file.is_valid()) {
|
||||
FML_DLOG(ERROR) << "Could not create temporary file.";
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!TruncateFile(temp_file, mapping.GetSize())) {
|
||||
FML_DLOG(ERROR) << "Could not truncate the file to the correct size. "
|
||||
<< GetLastErrorMessage();
|
||||
return false;
|
||||
}
|
||||
|
||||
{
|
||||
FileMapping temp_file_mapping(temp_file, {FileMapping::Protection::kRead,
|
||||
FileMapping::Protection::kWrite});
|
||||
if (temp_file_mapping.GetSize() != mapping.GetSize()) {
|
||||
FML_DLOG(ERROR) << "Temporary file mapping size was incorrect. Is "
|
||||
<< temp_file_mapping.GetSize() << ". Should be "
|
||||
<< mapping.GetSize() << ".";
|
||||
return false;
|
||||
}
|
||||
|
||||
if (temp_file_mapping.GetMutableMapping() == nullptr) {
|
||||
FML_DLOG(ERROR) << "Temporary file does not have a mutable mapping.";
|
||||
return false;
|
||||
}
|
||||
|
||||
::memcpy(temp_file_mapping.GetMutableMapping(), mapping.GetMapping(),
|
||||
mapping.GetSize());
|
||||
|
||||
if (!::FlushViewOfFile(temp_file_mapping.GetMutableMapping(),
|
||||
mapping.GetSize())) {
|
||||
FML_DLOG(ERROR) << "Could not flush file view. " << GetLastErrorMessage();
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!::FlushFileBuffers(temp_file.get())) {
|
||||
FML_DLOG(ERROR) << "Could not flush file buffers. "
|
||||
<< GetLastErrorMessage();
|
||||
return false;
|
||||
}
|
||||
|
||||
// File mapping is detroyed.
|
||||
}
|
||||
|
||||
temp_file.reset();
|
||||
|
||||
if (!::MoveFile(StringToWideString(temp_file_path).c_str(),
|
||||
StringToWideString(file_path).c_str())) {
|
||||
FML_DLOG(ERROR)
|
||||
<< "Could not replace temp file at correct path. File path: "
|
||||
<< file_path << ". Temp file path: " << temp_file_path << " "
|
||||
<< GetLastErrorMessage();
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace fml
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
#include <type_traits>
|
||||
|
||||
#include "flutter/fml/file.h"
|
||||
#include "flutter/fml/platform/win/errors_win.h"
|
||||
#include "flutter/fml/platform/win/wstring_conversion.h"
|
||||
|
||||
namespace fml {
|
||||
@@ -19,45 +20,79 @@ Mapping::Mapping() = default;
|
||||
|
||||
Mapping::~Mapping() = default;
|
||||
|
||||
FileMapping::FileMapping(const std::string& path, bool executable)
|
||||
: FileMapping(OpenFile(path.c_str(),
|
||||
executable ? OpenPermission::kExecute
|
||||
: OpenPermission::kRead,
|
||||
false),
|
||||
executable) {}
|
||||
static bool IsWritable(
|
||||
std::initializer_list<FileMapping::Protection> protection_flags) {
|
||||
for (auto protection : protection_flags) {
|
||||
if (protection == FileMapping::Protection::kWrite) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
FileMapping::FileMapping(const fml::UniqueFD& fd, bool executable)
|
||||
static bool IsExecutable(
|
||||
std::initializer_list<FileMapping::Protection> protection_flags) {
|
||||
for (auto protection : protection_flags) {
|
||||
if (protection == FileMapping::Protection::kExecute) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
FileMapping::FileMapping(const fml::UniqueFD& fd,
|
||||
std::initializer_list<Protection> protections)
|
||||
: size_(0), mapping_(nullptr) {
|
||||
if (!fd.is_valid()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (auto size = ::GetFileSize(fd.get(), nullptr)) {
|
||||
if (size > 0) {
|
||||
size_ = size;
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
const auto mapping_size = ::GetFileSize(fd.get(), nullptr);
|
||||
|
||||
if (mapping_size == INVALID_FILE_SIZE) {
|
||||
FML_DLOG(ERROR) << "Invalid file size. " << GetLastErrorMessage();
|
||||
return;
|
||||
}
|
||||
|
||||
const DWORD protect = executable ? PAGE_EXECUTE_READ : PAGE_READONLY;
|
||||
DWORD protect_flags = 0;
|
||||
bool read_only = !IsWritable(protections);
|
||||
|
||||
mapping_handle_.reset(::CreateFileMapping(fd.get(), // hFile
|
||||
nullptr, // lpAttributes
|
||||
protect, // flProtect
|
||||
0, // dwMaximumSizeHigh
|
||||
0, // dwMaximumSizeLow
|
||||
nullptr // lpName
|
||||
if (IsExecutable(protections)) {
|
||||
protect_flags = PAGE_EXECUTE_READ;
|
||||
} else if (read_only) {
|
||||
protect_flags = PAGE_READONLY;
|
||||
} else {
|
||||
protect_flags = PAGE_READWRITE;
|
||||
}
|
||||
|
||||
mapping_handle_.reset(::CreateFileMapping(fd.get(), // hFile
|
||||
nullptr, // lpAttributes
|
||||
protect_flags, // flProtect
|
||||
0, // dwMaximumSizeHigh
|
||||
0, // dwMaximumSizeLow
|
||||
nullptr // lpName
|
||||
));
|
||||
|
||||
if (!mapping_handle_.is_valid()) {
|
||||
return;
|
||||
}
|
||||
|
||||
const DWORD desired_access = executable ? FILE_MAP_ALL_ACCESS : FILE_MAP_READ;
|
||||
const DWORD desired_access = read_only ? FILE_MAP_READ : FILE_MAP_WRITE;
|
||||
|
||||
mapping_ = reinterpret_cast<uint8_t*>(
|
||||
MapViewOfFile(mapping_handle_.get(), desired_access, 0, 0, size_));
|
||||
auto mapping = reinterpret_cast<uint8_t*>(
|
||||
MapViewOfFile(mapping_handle_.get(), desired_access, 0, 0, mapping_size));
|
||||
|
||||
if (mapping == nullptr) {
|
||||
FML_DLOG(ERROR) << "Could not setup file mapping. "
|
||||
<< GetLastErrorMessage();
|
||||
return;
|
||||
}
|
||||
|
||||
mapping_ = mapping;
|
||||
size_ = mapping_size;
|
||||
if (IsWritable(protections)) {
|
||||
mutable_mapping_ = mapping_;
|
||||
}
|
||||
}
|
||||
|
||||
FileMapping::~FileMapping() {
|
||||
|
||||
@@ -90,5 +90,10 @@ std::string FromURI(const std::string& uri) {
|
||||
return SanitizeURIEscapedCharacters(file_path);
|
||||
}
|
||||
|
||||
fml::UniqueFD GetCachesDirectory() {
|
||||
// Unsupported on this platform.
|
||||
return {};
|
||||
}
|
||||
|
||||
} // namespace paths
|
||||
} // namespace fml
|
||||
|
||||
@@ -11,6 +11,9 @@
|
||||
|
||||
namespace fml {
|
||||
|
||||
using WideStringConvertor =
|
||||
std::wstring_convert<std::codecvt_utf8<wchar_t>, wchar_t>;
|
||||
|
||||
inline std::wstring ConvertToWString(const char* path) {
|
||||
if (path == nullptr) {
|
||||
return {};
|
||||
@@ -20,6 +23,16 @@ inline std::wstring ConvertToWString(const char* path) {
|
||||
return wchar_conv.from_bytes(path8);
|
||||
}
|
||||
|
||||
inline std::wstring StringToWideString(const std::string& str) {
|
||||
WideStringConvertor converter;
|
||||
return converter.from_bytes(str);
|
||||
}
|
||||
|
||||
inline std::string WideStringToString(const std::wstring& wstr) {
|
||||
WideStringConvertor converter;
|
||||
return converter.to_bytes(wstr);
|
||||
}
|
||||
|
||||
} // namespace fml
|
||||
|
||||
#endif // FLUTTER_FML_PLATFORM_WIN_WSTRING_CONVERSION_H_
|
||||
|
||||
@@ -43,7 +43,9 @@ static const char* kIsolateInstructionsSymbolSo =
|
||||
std::unique_ptr<DartSnapshotBuffer> ResolveVMData(const Settings& settings) {
|
||||
if (settings.vm_snapshot_data_path.size() > 0) {
|
||||
if (auto source = DartSnapshotBuffer::CreateWithContentsOfFile(
|
||||
settings.vm_snapshot_data_path.c_str(), false /* executable */)) {
|
||||
fml::OpenFile(settings.vm_snapshot_data_path.c_str(), false,
|
||||
fml::FilePermission::kRead),
|
||||
{fml::FileMapping::Protection::kRead})) {
|
||||
return source;
|
||||
}
|
||||
}
|
||||
@@ -66,7 +68,9 @@ std::unique_ptr<DartSnapshotBuffer> ResolveVMInstructions(
|
||||
const Settings& settings) {
|
||||
if (settings.vm_snapshot_instr_path.size() > 0) {
|
||||
if (auto source = DartSnapshotBuffer::CreateWithContentsOfFile(
|
||||
settings.vm_snapshot_instr_path.c_str(), true /* executable */)) {
|
||||
fml::OpenFile(settings.vm_snapshot_instr_path.c_str(), false,
|
||||
fml::FilePermission::kRead),
|
||||
{fml::FileMapping::Protection::kExecute})) {
|
||||
return source;
|
||||
}
|
||||
}
|
||||
@@ -89,8 +93,9 @@ std::unique_ptr<DartSnapshotBuffer> ResolveIsolateData(
|
||||
const Settings& settings) {
|
||||
if (settings.isolate_snapshot_data_path.size() > 0) {
|
||||
if (auto source = DartSnapshotBuffer::CreateWithContentsOfFile(
|
||||
settings.isolate_snapshot_data_path.c_str(),
|
||||
false /* executable */)) {
|
||||
fml::OpenFile(settings.isolate_snapshot_data_path.c_str(), false,
|
||||
fml::FilePermission::kRead),
|
||||
{fml::FileMapping::Protection::kRead})) {
|
||||
return source;
|
||||
}
|
||||
}
|
||||
@@ -113,8 +118,9 @@ std::unique_ptr<DartSnapshotBuffer> ResolveIsolateInstructions(
|
||||
const Settings& settings) {
|
||||
if (settings.isolate_snapshot_instr_path.size() > 0) {
|
||||
if (auto source = DartSnapshotBuffer::CreateWithContentsOfFile(
|
||||
settings.isolate_snapshot_instr_path.c_str(),
|
||||
true /* executable */)) {
|
||||
fml::OpenFile(settings.isolate_snapshot_instr_path.c_str(), false,
|
||||
fml::FilePermission::kRead),
|
||||
{fml::FileMapping::Protection::kExecute})) {
|
||||
return source;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -33,8 +33,10 @@ class NativeLibrarySnapshotBuffer final : public DartSnapshotBuffer {
|
||||
|
||||
class FileSnapshotBuffer final : public DartSnapshotBuffer {
|
||||
public:
|
||||
FileSnapshotBuffer(const char* path, bool executable)
|
||||
: mapping_(path, executable) {
|
||||
FileSnapshotBuffer(
|
||||
const fml::UniqueFD& fd,
|
||||
std::initializer_list<fml::FileMapping::Protection> protection)
|
||||
: mapping_(fd, protection) {
|
||||
if (mapping_.GetSize() > 0) {
|
||||
symbol_ = mapping_.GetMapping();
|
||||
}
|
||||
@@ -75,9 +77,10 @@ DartSnapshotBuffer::CreateWithSymbolInLibrary(
|
||||
}
|
||||
|
||||
std::unique_ptr<DartSnapshotBuffer>
|
||||
DartSnapshotBuffer::CreateWithContentsOfFile(const char* file_path,
|
||||
bool executable) {
|
||||
auto source = std::make_unique<FileSnapshotBuffer>(file_path, executable);
|
||||
DartSnapshotBuffer::CreateWithContentsOfFile(
|
||||
const fml::UniqueFD& fd,
|
||||
std::initializer_list<fml::FileMapping::Protection> protection) {
|
||||
auto source = std::make_unique<FileSnapshotBuffer>(fd, protection);
|
||||
return source->GetSnapshotPointer() == nullptr ? nullptr : std::move(source);
|
||||
}
|
||||
|
||||
|
||||
@@ -5,9 +5,12 @@
|
||||
#ifndef FLUTTER_RUNTIME_DART_SNAPSHOT_BUFFER_H_
|
||||
#define FLUTTER_RUNTIME_DART_SNAPSHOT_BUFFER_H_
|
||||
|
||||
#include <initializer_list>
|
||||
#include <memory>
|
||||
|
||||
#include "flutter/fml/file.h"
|
||||
#include "flutter/fml/macros.h"
|
||||
#include "flutter/fml/mapping.h"
|
||||
#include "flutter/fml/native_library.h"
|
||||
|
||||
namespace blink {
|
||||
@@ -19,8 +22,8 @@ class DartSnapshotBuffer {
|
||||
const char* symbol_name);
|
||||
|
||||
static std::unique_ptr<DartSnapshotBuffer> CreateWithContentsOfFile(
|
||||
const char* file_path,
|
||||
bool executable);
|
||||
const fml::UniqueFD& fd,
|
||||
std::initializer_list<fml::FileMapping::Protection> protection);
|
||||
|
||||
static std::unique_ptr<DartSnapshotBuffer> CreateWithUnmanagedAllocation(
|
||||
const uint8_t* allocation);
|
||||
|
||||
@@ -67,6 +67,8 @@ source_set("common") {
|
||||
"io_manager.h",
|
||||
"isolate_configuration.cc",
|
||||
"isolate_configuration.h",
|
||||
"persistent_cache.cc",
|
||||
"persistent_cache.h",
|
||||
"platform_view.cc",
|
||||
"platform_view.h",
|
||||
"rasterizer.cc",
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
#include "flutter/shell/common/io_manager.h"
|
||||
|
||||
#include "flutter/fml/message_loop.h"
|
||||
#include "flutter/shell/common/persistent_cache.h"
|
||||
#include "third_party/skia/include/gpu/gl/GrGLInterface.h"
|
||||
|
||||
namespace shell {
|
||||
@@ -17,6 +18,8 @@ sk_sp<GrContext> IOManager::CreateCompatibleResourceLoadingContext(
|
||||
|
||||
GrContextOptions options = {};
|
||||
|
||||
options.fPersistentCache = PersistentCache::GetCacheForProcess();
|
||||
|
||||
// There is currently a bug with doing GPU YUV to RGB conversions on the IO
|
||||
// thread. The necessary work isn't being flushed or synchronized with the
|
||||
// other threads correctly, so the textures end up blank. For now, suppress
|
||||
|
||||
102
engine/src/flutter/shell/common/persistent_cache.cc
Normal file
102
engine/src/flutter/shell/common/persistent_cache.cc
Normal file
@@ -0,0 +1,102 @@
|
||||
// Copyright 2018 The Flutter 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 "flutter/shell/common/persistent_cache.h"
|
||||
|
||||
#include <memory>
|
||||
#include <string>
|
||||
|
||||
#include "flutter/fml/base32.h"
|
||||
#include "flutter/fml/file.h"
|
||||
#include "flutter/fml/mapping.h"
|
||||
#include "flutter/fml/paths.h"
|
||||
#include "flutter/fml/trace_event.h"
|
||||
#include "flutter/shell/version/version.h"
|
||||
|
||||
namespace shell {
|
||||
|
||||
static std::string SkKeyToFilePath(const SkData& data) {
|
||||
if (data.data() == nullptr || data.size() == 0) {
|
||||
return "";
|
||||
}
|
||||
|
||||
fml::StringView view(reinterpret_cast<const char*>(data.data()), data.size());
|
||||
|
||||
auto encode_result = fml::Base32Encode(view);
|
||||
|
||||
if (!encode_result.first) {
|
||||
return "";
|
||||
}
|
||||
|
||||
return encode_result.second;
|
||||
}
|
||||
|
||||
PersistentCache* PersistentCache::GetCacheForProcess() {
|
||||
static std::unique_ptr<PersistentCache> gPersistentCache;
|
||||
static std::once_flag once = {};
|
||||
std::call_once(once, []() { gPersistentCache.reset(new PersistentCache()); });
|
||||
return gPersistentCache.get();
|
||||
}
|
||||
|
||||
PersistentCache::PersistentCache()
|
||||
: cache_directory_(CreateDirectory(fml::paths::GetCachesDirectory(),
|
||||
{
|
||||
"flutter_engine", //
|
||||
GetFlutterEngineVersion(), //
|
||||
"skia", //
|
||||
GetSkiaVersion() //
|
||||
},
|
||||
fml::FilePermission::kReadWrite)) {
|
||||
if (!cache_directory_.is_valid()) {
|
||||
FML_LOG(ERROR) << "Could not acquire the persistent cache directory. "
|
||||
"Caching of GPU resources on disk is disabled.";
|
||||
}
|
||||
}
|
||||
|
||||
PersistentCache::~PersistentCache() = default;
|
||||
|
||||
// |GrContextOptions::PersistentCache|
|
||||
sk_sp<SkData> PersistentCache::load(const SkData& key) {
|
||||
TRACE_EVENT0("flutter", "PersistentCacheLoad");
|
||||
if (!cache_directory_.is_valid()) {
|
||||
return nullptr;
|
||||
}
|
||||
auto file_name = SkKeyToFilePath(key);
|
||||
if (file_name.size() == 0) {
|
||||
return nullptr;
|
||||
}
|
||||
auto file = fml::OpenFile(cache_directory_, file_name.c_str(), false,
|
||||
fml::FilePermission::kRead);
|
||||
if (!file.is_valid()) {
|
||||
return nullptr;
|
||||
}
|
||||
auto mapping = std::make_unique<fml::FileMapping>(file);
|
||||
if (mapping->GetSize() == 0) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
TRACE_EVENT0("flutter", "PersistentCacheLoadHit");
|
||||
return SkData::MakeWithCopy(mapping->GetMapping(), mapping->GetSize());
|
||||
}
|
||||
|
||||
// |GrContextOptions::PersistentCache|
|
||||
void PersistentCache::store(const SkData& key, const SkData& data) {
|
||||
TRACE_EVENT0("flutter", "PersistentCacheStore");
|
||||
if (!cache_directory_.is_valid()) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto file_name = SkKeyToFilePath(key);
|
||||
auto mapping =
|
||||
std::make_unique<fml::NonOwnedMapping>(data.bytes(), data.size());
|
||||
|
||||
if (!fml::WriteAtomically(cache_directory_, //
|
||||
file_name.c_str(), //
|
||||
*mapping) //
|
||||
) {
|
||||
FML_DLOG(ERROR) << "Could not write cache contents to persistent store.";
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace shell
|
||||
38
engine/src/flutter/shell/common/persistent_cache.h
Normal file
38
engine/src/flutter/shell/common/persistent_cache.h
Normal file
@@ -0,0 +1,38 @@
|
||||
// Copyright 2018 The Flutter Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#ifndef FLUTTER_SHELL_COMMON_PERSISTENT_CACHE_H_
|
||||
#define FLUTTER_SHELL_COMMON_PERSISTENT_CACHE_H_
|
||||
|
||||
#include <mutex>
|
||||
|
||||
#include "flutter/fml/macros.h"
|
||||
#include "flutter/fml/unique_fd.h"
|
||||
#include "third_party/skia/include/gpu/GrContextOptions.h"
|
||||
|
||||
namespace shell {
|
||||
|
||||
class PersistentCache : public GrContextOptions::PersistentCache {
|
||||
public:
|
||||
static PersistentCache* GetCacheForProcess();
|
||||
|
||||
~PersistentCache() override;
|
||||
|
||||
private:
|
||||
fml::UniqueFD cache_directory_;
|
||||
|
||||
PersistentCache();
|
||||
|
||||
// |GrContextOptions::PersistentCache|
|
||||
sk_sp<SkData> load(const SkData& key) override;
|
||||
|
||||
// |GrContextOptions::PersistentCache|
|
||||
void store(const SkData& key, const SkData& data) override;
|
||||
|
||||
FML_DISALLOW_COPY_AND_ASSIGN(PersistentCache);
|
||||
};
|
||||
|
||||
} // namespace shell
|
||||
|
||||
#endif // FLUTTER_SHELL_COMMON_PERSISTENT_CACHE_H_
|
||||
@@ -20,8 +20,8 @@ RunConfiguration RunConfiguration::InferFromSettings(
|
||||
fml::Duplicate(settings.assets_dir)));
|
||||
|
||||
asset_manager->PushBack(
|
||||
std::make_unique<blink::DirectoryAssetBundle>(fml::OpenFile(
|
||||
settings.assets_path.c_str(), fml::OpenPermission::kRead, true)));
|
||||
std::make_unique<blink::DirectoryAssetBundle>(fml::OpenDirectory(
|
||||
settings.assets_path.c_str(), false, fml::FilePermission::kRead)));
|
||||
|
||||
return {IsolateConfiguration::InferFromSettings(settings, asset_manager),
|
||||
asset_manager};
|
||||
|
||||
@@ -873,7 +873,8 @@ bool Shell::OnServiceProtocolRunInView(
|
||||
fml::paths::FromURI(params.at("assetDirectory").ToString());
|
||||
|
||||
auto main_script_file_mapping =
|
||||
std::make_unique<fml::FileMapping>(main_script_path, false);
|
||||
std::make_unique<fml::FileMapping>(fml::OpenFile(
|
||||
main_script_path.c_str(), false, fml::FilePermission::kRead));
|
||||
|
||||
auto isolate_configuration = IsolateConfiguration::CreateForKernel(
|
||||
std::move(main_script_file_mapping));
|
||||
@@ -881,8 +882,8 @@ bool Shell::OnServiceProtocolRunInView(
|
||||
RunConfiguration configuration(std::move(isolate_configuration));
|
||||
|
||||
configuration.AddAssetResolver(
|
||||
std::make_unique<blink::DirectoryAssetBundle>(fml::OpenFile(
|
||||
asset_directory_path.c_str(), fml::OpenPermission::kRead, true)));
|
||||
std::make_unique<blink::DirectoryAssetBundle>(fml::OpenDirectory(
|
||||
asset_directory_path.c_str(), false, fml::FilePermission::kRead)));
|
||||
|
||||
auto& allocator = response.GetAllocator();
|
||||
response.SetObject();
|
||||
@@ -938,8 +939,8 @@ bool Shell::OnServiceProtocolSetAssetBundlePath(
|
||||
auto asset_manager = fml::MakeRefCounted<blink::AssetManager>();
|
||||
|
||||
asset_manager->PushFront(std::make_unique<blink::DirectoryAssetBundle>(
|
||||
fml::OpenFile(params.at("assetDirectory").ToString().c_str(),
|
||||
fml::OpenPermission::kRead, true)));
|
||||
fml::OpenDirectory(params.at("assetDirectory").ToString().c_str(), false,
|
||||
fml::FilePermission::kRead)));
|
||||
|
||||
if (engine_->UpdateAssetManager(std::move(asset_manager))) {
|
||||
response.AddMember("type", "Success", allocator);
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
#include "flutter/fml/arraysize.h"
|
||||
#include "flutter/fml/logging.h"
|
||||
#include "flutter/fml/trace_event.h"
|
||||
#include "flutter/shell/common/persistent_cache.h"
|
||||
#include "third_party/skia/include/core/SkColorFilter.h"
|
||||
#include "third_party/skia/include/core/SkSurface.h"
|
||||
#include "third_party/skia/include/gpu/GrBackendSurface.h"
|
||||
@@ -46,6 +47,9 @@ GPUSurfaceGL::GPUSurfaceGL(GPUSurfaceGLDelegate* delegate)
|
||||
proc_resolver_ = delegate_->GetGLProcResolver();
|
||||
|
||||
GrContextOptions options;
|
||||
|
||||
options.fPersistentCache = PersistentCache::GetCacheForProcess();
|
||||
|
||||
options.fAvoidStencilBuffers = true;
|
||||
|
||||
// To get video playback on the widest range of devices, we limit Skia to
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
#include "flutter/fml/message_loop.h"
|
||||
#include "flutter/fml/paths.h"
|
||||
#include "flutter/fml/platform/android/jni_util.h"
|
||||
#include "flutter/fml/platform/android/paths_android.h"
|
||||
#include "flutter/lib/ui/plugins/callback_cache.h"
|
||||
#include "flutter/runtime/dart_vm.h"
|
||||
#include "flutter/runtime/start_up.h"
|
||||
@@ -46,7 +47,8 @@ void FlutterMain::Init(JNIEnv* env,
|
||||
jobject context,
|
||||
jobjectArray jargs,
|
||||
jstring bundlePath,
|
||||
jstring appStoragePath) {
|
||||
jstring appStoragePath,
|
||||
jstring engineCachesPath) {
|
||||
std::vector<std::string> args;
|
||||
args.push_back("flutter");
|
||||
for (auto& arg : fml::jni::StringArrayToVector(env, jargs)) {
|
||||
@@ -59,8 +61,14 @@ void FlutterMain::Init(JNIEnv* env,
|
||||
settings.assets_path = fml::jni::JavaStringToString(env, bundlePath);
|
||||
|
||||
// Restore the callback cache.
|
||||
// TODO(chinmaygarde): Route all cache file access through FML and remove this
|
||||
// setter.
|
||||
blink::DartCallbackCache::SetCachePath(
|
||||
fml::jni::JavaStringToString(env, appStoragePath));
|
||||
|
||||
fml::paths::InitializeAndroidCachesPath(
|
||||
fml::jni::JavaStringToString(env, engineCachesPath));
|
||||
|
||||
blink::DartCallbackCache::LoadCacheFromDisk();
|
||||
|
||||
if (!blink::DartVM::IsRunningPrecompiledCode()) {
|
||||
@@ -99,7 +107,7 @@ bool FlutterMain::Register(JNIEnv* env) {
|
||||
{
|
||||
.name = "nativeInit",
|
||||
.signature = "(Landroid/content/Context;[Ljava/lang/String;Ljava/"
|
||||
"lang/String;Ljava/lang/String;)V",
|
||||
"lang/String;Ljava/lang/String;Ljava/lang/String;)V",
|
||||
.fnPtr = reinterpret_cast<void*>(&Init),
|
||||
},
|
||||
{
|
||||
|
||||
@@ -32,7 +32,8 @@ class FlutterMain {
|
||||
jobject context,
|
||||
jobjectArray jargs,
|
||||
jstring bundlePath,
|
||||
jstring appRootPath);
|
||||
jstring appRootPath,
|
||||
jstring engineCachesPath);
|
||||
|
||||
FML_DISALLOW_COPY_AND_ASSIGN(FlutterMain);
|
||||
};
|
||||
|
||||
@@ -214,8 +214,9 @@ public class FlutterMain {
|
||||
|
||||
String appBundlePath = findAppBundlePath(applicationContext);
|
||||
String appStoragePath = PathUtils.getFilesDir(applicationContext);
|
||||
String engineCachesPath = PathUtils.getCacheDirectory(applicationContext);
|
||||
nativeInit(applicationContext, shellArgs.toArray(new String[0]),
|
||||
appBundlePath, appStoragePath);
|
||||
appBundlePath, appStoragePath, engineCachesPath);
|
||||
|
||||
sInitialized = true;
|
||||
} catch (Exception e) {
|
||||
@@ -224,7 +225,7 @@ public class FlutterMain {
|
||||
}
|
||||
}
|
||||
|
||||
private static native void nativeInit(Context context, String[] args, String bundlePath, String appStoragePath);
|
||||
private static native void nativeInit(Context context, String[] args, String bundlePath, String appStoragePath, String engineCachesPath);
|
||||
private static native void nativeRecordStartTimestamp(long initTimeMillis);
|
||||
|
||||
/**
|
||||
|
||||
@@ -252,8 +252,9 @@ static void RunBundleAndSnapshotFromLibrary(JNIEnv* env,
|
||||
asset_manager->PushBack(
|
||||
std::make_unique<blink::ZipAssetStore>(bundlepath));
|
||||
} else {
|
||||
asset_manager->PushBack(std::make_unique<blink::DirectoryAssetBundle>(
|
||||
fml::OpenFile(bundlepath.c_str(), fml::OpenPermission::kRead, true)));
|
||||
asset_manager->PushBack(
|
||||
std::make_unique<blink::DirectoryAssetBundle>(fml::OpenDirectory(
|
||||
bundlepath.c_str(), false, fml::FilePermission::kRead)));
|
||||
}
|
||||
|
||||
// Use the last path component of the bundle path to determine the
|
||||
@@ -273,8 +274,9 @@ static void RunBundleAndSnapshotFromLibrary(JNIEnv* env,
|
||||
|
||||
const auto defaultpath = fml::jni::JavaStringToString(env, jdefaultPath);
|
||||
if (defaultpath.size() > 0) {
|
||||
asset_manager->PushBack(std::make_unique<blink::DirectoryAssetBundle>(
|
||||
fml::OpenFile(defaultpath.c_str(), fml::OpenPermission::kRead, true)));
|
||||
asset_manager->PushBack(
|
||||
std::make_unique<blink::DirectoryAssetBundle>(fml::OpenDirectory(
|
||||
defaultpath.c_str(), false, fml::FilePermission::kRead)));
|
||||
}
|
||||
|
||||
auto isolate_configuration = CreateIsolateConfiguration(*asset_manager);
|
||||
|
||||
@@ -370,8 +370,8 @@ FlutterResult FlutterEngineRun(size_t version,
|
||||
fml::Duplicate(settings.assets_dir)));
|
||||
|
||||
run_configuration.AddAssetResolver(
|
||||
std::make_unique<blink::DirectoryAssetBundle>(fml::OpenFile(
|
||||
settings.assets_path.c_str(), fml::OpenPermission::kRead, true)));
|
||||
std::make_unique<blink::DirectoryAssetBundle>(fml::OpenDirectory(
|
||||
settings.assets_path.c_str(), false, fml::FilePermission::kRead)));
|
||||
|
||||
if (!embedder_engine->Run(std::move(run_configuration))) {
|
||||
return kInvalidArguments;
|
||||
|
||||
@@ -129,8 +129,13 @@ int RunTester(const blink::Settings& settings, bool run_forever) {
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
std::initializer_list<fml::FileMapping::Protection> protection = {
|
||||
fml::FileMapping::Protection::kRead};
|
||||
auto main_dart_file_mapping = std::make_unique<fml::FileMapping>(
|
||||
fml::paths::AbsolutePath(settings.main_dart_file_path), false);
|
||||
fml::OpenFile(
|
||||
fml::paths::AbsolutePath(settings.main_dart_file_path).c_str(), false,
|
||||
fml::FilePermission::kRead),
|
||||
protection);
|
||||
|
||||
auto isolate_configuration =
|
||||
IsolateConfiguration::CreateForKernel(std::move(main_dart_file_mapping));
|
||||
@@ -144,8 +149,8 @@ int RunTester(const blink::Settings& settings, bool run_forever) {
|
||||
asset_manager->PushBack(std::make_unique<blink::DirectoryAssetBundle>(
|
||||
fml::Duplicate(settings.assets_dir)));
|
||||
asset_manager->PushBack(
|
||||
std::make_unique<blink::DirectoryAssetBundle>(fml::OpenFile(
|
||||
settings.assets_path.c_str(), fml::OpenPermission::kRead, true)));
|
||||
std::make_unique<blink::DirectoryAssetBundle>(fml::OpenDirectory(
|
||||
settings.assets_path.c_str(), false, fml::FilePermission::kRead)));
|
||||
|
||||
RunConfiguration run_configuration(std::move(isolate_configuration),
|
||||
std::move(asset_manager));
|
||||
|
||||
Reference in New Issue
Block a user