Merge UP1A.230119.002
Change-Id: I7ed93ddd712083f5a5e93811c576ba600c104794
This commit is contained in:
commit
65f954819e
|
@ -40,15 +40,6 @@ on post-fs-data
|
|||
chown system log /data/misc/bootstat/time_since_last_boot
|
||||
# end ota transitional support
|
||||
|
||||
# Record the time at which the user has successfully entered the pin to decrypt
|
||||
# the device, /data is decrypted, and the system is entering the main boot phase.
|
||||
#
|
||||
# post-fs-data: /data is writable
|
||||
# property:init.svc.bootanim=running: The boot animation is running
|
||||
# property:ro.crypto.type=block: FDE device
|
||||
on post-fs-data && property:init.svc.bootanim=running && property:ro.crypto.type=block
|
||||
exec_background - system log -- /system/bin/bootstat -r post_decrypt_time_elapsed
|
||||
|
||||
# Initialize bootstat state machine.
|
||||
#
|
||||
# sys.bootstat.first_boot_completed: responsible for making sure that record_boot_complete happens
|
||||
|
|
|
@ -88,7 +88,7 @@ GwpAsanCrashData::GwpAsanCrashData(unwindstack::Memory* process_memory,
|
|||
thread_id_ = thread_info.tid;
|
||||
|
||||
// Grab the internal error address, if it exists.
|
||||
uintptr_t internal_crash_address = __gwp_asan_get_internal_crash_address(&state_);
|
||||
uintptr_t internal_crash_address = __gwp_asan_get_internal_crash_address(&state_, crash_address_);
|
||||
if (internal_crash_address) {
|
||||
crash_address_ = internal_crash_address;
|
||||
}
|
||||
|
|
|
@ -44,9 +44,12 @@ ScudoCrashData::ScudoCrashData(unwindstack::Memory* process_memory,
|
|||
__scudo_get_stack_depot_size());
|
||||
auto region_info = AllocAndReadFully(process_memory, process_info.scudo_region_info,
|
||||
__scudo_get_region_info_size());
|
||||
auto ring_buffer = AllocAndReadFully(process_memory, process_info.scudo_ring_buffer,
|
||||
process_info.scudo_ring_buffer_size);
|
||||
if (!stack_depot || !region_info || !ring_buffer) {
|
||||
std::unique_ptr<char[]> ring_buffer;
|
||||
if (process_info.scudo_ring_buffer_size != 0) {
|
||||
ring_buffer = AllocAndReadFully(process_memory, process_info.scudo_ring_buffer,
|
||||
process_info.scudo_ring_buffer_size);
|
||||
}
|
||||
if (!stack_depot || !region_info) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
@ -1082,7 +1082,8 @@ static void flash_buf(const std::string& partition, struct fastboot_buffer* buf)
|
|||
sparse_file** s;
|
||||
|
||||
if (partition == "boot" || partition == "boot_a" || partition == "boot_b" ||
|
||||
partition == "init_boot" || partition == "init_boot_a" || partition == "init_boot_b") {
|
||||
partition == "init_boot" || partition == "init_boot_a" || partition == "init_boot_b" ||
|
||||
partition == "recovery" || partition == "recovery_a" || partition == "recovery_b") {
|
||||
copy_avb_footer(partition, buf);
|
||||
}
|
||||
|
||||
|
|
|
@ -27,5 +27,16 @@
|
|||
{
|
||||
"name": "cow_api_test"
|
||||
}
|
||||
],
|
||||
"kernel-presubmit": [
|
||||
{
|
||||
"name": "vts_libdm_test"
|
||||
},
|
||||
{
|
||||
"name": "vts_core_liblp_test"
|
||||
},
|
||||
{
|
||||
"name": "vts_libsnapshot_test"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
|
@ -305,19 +305,16 @@ bool ParseFsMgrFlags(const std::string& flags, FstabEntry* entry) {
|
|||
if (!ParseByteCount(arg, &entry->zram_backingdev_size)) {
|
||||
LWARNING << "Warning: zram_backingdev_size= flag malformed: " << arg;
|
||||
}
|
||||
} else if (StartsWith(flag, "zoned_device=")) {
|
||||
std::string zoned;
|
||||
if (ReadFileToString("/sys/class/block/" + arg + "/queue/zoned", &zoned) &&
|
||||
android::base::StartsWith(zoned, "host-managed")) {
|
||||
entry->zoned_device = "/dev/block/" + arg;
|
||||
} else if (flag == "zoned_device") {
|
||||
if (access("/dev/block/by-name/zoned_device", F_OK) == 0) {
|
||||
entry->zoned_device = "/dev/block/by-name/zoned_device";
|
||||
|
||||
// atgc in f2fs does not support a zoned device
|
||||
auto options = Split(entry->fs_options, ",");
|
||||
options.erase(std::remove(options.begin(), options.end(), "atgc"), options.end());
|
||||
entry->fs_options = android::base::Join(options, ",");
|
||||
LINFO << "Removed ATGC in fs_options as " << entry->fs_options;
|
||||
} else {
|
||||
LWARNING << "Warning: cannot find the zoned device: " << arg;
|
||||
LINFO << "Removed ATGC in fs_options as " << entry->fs_options
|
||||
<< " for zoned device=" << entry->zoned_device;
|
||||
}
|
||||
} else {
|
||||
LWARNING << "Warning: unknown flag: " << flag;
|
||||
|
|
|
@ -35,18 +35,18 @@ images. After `/data` is mounted however, there are two problems:
|
|||
|
||||
We break the problem down into three scenarios.
|
||||
|
||||
### FDE and Metadata Encrypted Devices
|
||||
### Metadata Encrypted Devices
|
||||
|
||||
When FDE or metadata encryption is used, `/data` is not mounted from
|
||||
When metadata encryption is used, `/data` is not mounted from
|
||||
`/dev/block/by-name/data`. Instead, it is mounted from an intermediate
|
||||
`dm-crypt` or `dm-default-key` device. This means the underlying device is
|
||||
not marked in use, and we can create new dm-linear devices on top of it.
|
||||
`dm-default-key` device. This means the underlying device is not marked in use,
|
||||
and we can create new dm-linear devices on top of it.
|
||||
|
||||
On these devices, a block device for an image will consist of a single
|
||||
device-mapper device with a `dm-linear` table entry for each extent in the
|
||||
backing file.
|
||||
|
||||
### Unencrypted and FBE-encrypted Devices
|
||||
### Unencrypted and FBE-only Devices
|
||||
|
||||
When a device is unencrypted, or is encrypted with FBE but not metadata
|
||||
encryption, we instead use a loop device with `LOOP_SET_DIRECT_IO` enabled.
|
||||
|
|
|
@ -1498,6 +1498,7 @@ void SnapshotManager::AcknowledgeMergeSuccess(LockedFile* lock) {
|
|||
if (UpdateUsesUserSnapshots(lock) && !device()->IsTestDevice()) {
|
||||
if (snapuserd_client_) {
|
||||
snapuserd_client_->DetachSnapuserd();
|
||||
snapuserd_client_->RemoveTransitionedDaemonIndicator();
|
||||
snapuserd_client_ = nullptr;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -37,11 +37,13 @@ cc_defaults {
|
|||
cc_library_static {
|
||||
name: "libsnapshot_snapuserd",
|
||||
defaults: [
|
||||
"fs_mgr_defaults",
|
||||
"libsnapshot_snapuserd_defaults",
|
||||
],
|
||||
recovery_available: true,
|
||||
static_libs: [
|
||||
"libcutils_sockets",
|
||||
"libfs_mgr",
|
||||
],
|
||||
shared_libs: [
|
||||
"libbase",
|
||||
|
@ -49,6 +51,7 @@ cc_library_static {
|
|||
],
|
||||
export_include_dirs: ["include"],
|
||||
ramdisk_available: true,
|
||||
vendor_ramdisk_available: true,
|
||||
}
|
||||
|
||||
cc_defaults {
|
||||
|
@ -86,6 +89,7 @@ cc_defaults {
|
|||
"libgflags",
|
||||
"liblog",
|
||||
"libsnapshot_cow",
|
||||
"libsnapshot_snapuserd",
|
||||
"libz",
|
||||
"liblz4",
|
||||
"libext4_utils",
|
||||
|
|
|
@ -32,6 +32,7 @@ static constexpr uint32_t PACKET_SIZE = 512;
|
|||
|
||||
static constexpr char kSnapuserdSocket[] = "snapuserd";
|
||||
static constexpr char kSnapuserdSocketProxy[] = "snapuserd_proxy";
|
||||
static constexpr char kDaemonAliveIndicator[] = "daemon-alive-indicator";
|
||||
|
||||
// Ensure that the second-stage daemon for snapuserd is running.
|
||||
bool EnsureSnapuserdStarted();
|
||||
|
@ -44,9 +45,11 @@ class SnapuserdClient {
|
|||
std::string Receivemsg();
|
||||
|
||||
bool ValidateConnection();
|
||||
std::string GetDaemonAliveIndicatorPath();
|
||||
|
||||
public:
|
||||
explicit SnapuserdClient(android::base::unique_fd&& sockfd);
|
||||
SnapuserdClient(){};
|
||||
|
||||
static std::unique_ptr<SnapuserdClient> Connect(const std::string& socket_name,
|
||||
std::chrono::milliseconds timeout_ms);
|
||||
|
@ -91,6 +94,17 @@ class SnapuserdClient {
|
|||
// Check the update verification status - invoked by update_verifier during
|
||||
// boot
|
||||
bool QueryUpdateVerification();
|
||||
|
||||
// Check if Snapuser daemon is ready post selinux transition after OTA boot
|
||||
// This is invoked only by init as there is no sockets setup yet during
|
||||
// selinux transition
|
||||
bool IsTransitionedDaemonReady();
|
||||
|
||||
// Remove the daemon-alive-indicator path post snapshot merge
|
||||
bool RemoveTransitionedDaemonIndicator();
|
||||
|
||||
// Notify init that snapuserd daemon is ready post selinux transition
|
||||
void NotifyTransitionDaemonIsReady();
|
||||
};
|
||||
|
||||
} // namespace snapshot
|
||||
|
|
|
@ -29,10 +29,12 @@
|
|||
#include <chrono>
|
||||
#include <sstream>
|
||||
|
||||
#include <android-base/file.h>
|
||||
#include <android-base/logging.h>
|
||||
#include <android-base/parseint.h>
|
||||
#include <android-base/properties.h>
|
||||
#include <android-base/strings.h>
|
||||
#include <fs_mgr/file_wait.h>
|
||||
#include <snapuserd/snapuserd_client.h>
|
||||
|
||||
namespace android {
|
||||
|
@ -279,5 +281,42 @@ bool SnapuserdClient::QueryUpdateVerification() {
|
|||
return response == "success";
|
||||
}
|
||||
|
||||
std::string SnapuserdClient::GetDaemonAliveIndicatorPath() {
|
||||
return "/metadata/ota/" + std::string(kDaemonAliveIndicator);
|
||||
}
|
||||
|
||||
bool SnapuserdClient::IsTransitionedDaemonReady() {
|
||||
if (!android::fs_mgr::WaitForFile(GetDaemonAliveIndicatorPath(), 10s)) {
|
||||
LOG(ERROR) << "Timed out waiting for daemon indicator path: "
|
||||
<< GetDaemonAliveIndicatorPath();
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SnapuserdClient::RemoveTransitionedDaemonIndicator() {
|
||||
std::string error;
|
||||
std::string filePath = GetDaemonAliveIndicatorPath();
|
||||
if (!android::base::RemoveFileIfExists(filePath, &error)) {
|
||||
LOG(ERROR) << "Failed to remove DaemonAliveIndicatorPath - error: " << error;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!android::fs_mgr::WaitForFileDeleted(filePath, 5s)) {
|
||||
LOG(ERROR) << "Timed out waiting for " << filePath << " to unlink";
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void SnapuserdClient::NotifyTransitionDaemonIsReady() {
|
||||
if (!android::base::WriteStringToFile("1", GetDaemonAliveIndicatorPath())) {
|
||||
PLOG(ERROR) << "Unable to write daemon alive indicator path: "
|
||||
<< GetDaemonAliveIndicatorPath();
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace snapshot
|
||||
} // namespace android
|
||||
|
|
|
@ -119,6 +119,12 @@ bool Daemon::StartServerForUserspaceSnapshots(int arg_start, int argc, char** ar
|
|||
}
|
||||
}
|
||||
|
||||
// We reach this point only during selinux transition during device boot.
|
||||
// At this point, all threads are spin up and are ready to serve the I/O
|
||||
// requests for dm-user. Lets inform init.
|
||||
auto client = std::make_unique<SnapuserdClient>();
|
||||
client->NotifyTransitionDaemonIsReady();
|
||||
|
||||
// Skip the accept() call to avoid spurious log spam. The server will still
|
||||
// run until all handlers have completed.
|
||||
return user_server_.WaitForSocket();
|
||||
|
|
|
@ -454,15 +454,7 @@ cc_test {
|
|||
defaults: ["init_defaults"],
|
||||
require_root: true,
|
||||
|
||||
compile_multilib: "both",
|
||||
multilib: {
|
||||
lib32: {
|
||||
suffix: "32",
|
||||
},
|
||||
lib64: {
|
||||
suffix: "64",
|
||||
},
|
||||
},
|
||||
compile_multilib: "first",
|
||||
|
||||
srcs: [
|
||||
"devices_test.cpp",
|
||||
|
|
|
@ -22,7 +22,6 @@
|
|||
<target_preparer class="com.android.compatibility.common.tradefed.targetprep.FilePusher">
|
||||
<option name="cleanup" value="true" />
|
||||
<option name="push" value="CtsInitTestCases->/data/local/tmp/CtsInitTestCases" />
|
||||
<option name="append-bitness" value="true" />
|
||||
</target_preparer>
|
||||
<target_preparer class="com.android.tradefed.targetprep.RootTargetPreparer">
|
||||
<option name="throw-on-error" value="false" />
|
||||
|
|
|
@ -174,6 +174,17 @@ If the property `true` becomes `true` *AFTER* `boot` was triggered, nothing will
|
|||
be executed. The condition `boot && property:true=true` will be evaluated to
|
||||
false because the `boot` trigger is a past event.
|
||||
|
||||
Note that when `ro.property_service.async_persist_writes` is `true`, there is no
|
||||
defined ordering between persistent setprops and non-persistent setprops. For
|
||||
example:
|
||||
|
||||
on boot
|
||||
setprop a 1
|
||||
setprop persist.b 2
|
||||
|
||||
When `ro.property_service.async_persist_writes` is `true`, triggers for these
|
||||
two properties may execute in any order.
|
||||
|
||||
Services
|
||||
--------
|
||||
Services are programs which init launches and (optionally) restarts
|
||||
|
|
|
@ -431,6 +431,12 @@ std::vector<std::string> DeviceHandler::GetBlockDeviceSymlinks(const Uevent& uev
|
|||
}
|
||||
}
|
||||
|
||||
std::string model;
|
||||
if (ReadFileToString("/sys/class/block/" + uevent.device_name + "/queue/zoned", &model) &&
|
||||
!StartsWith(model, "none")) {
|
||||
links.emplace_back("/dev/block/by-name/zoned_device");
|
||||
}
|
||||
|
||||
auto last_slash = uevent.path.rfind('/');
|
||||
links.emplace_back(link_path + "/" + uevent.path.substr(last_slash + 1));
|
||||
|
||||
|
|
|
@ -98,6 +98,9 @@ using android::sysprop::InitProperties::is_userspace_reboot_supported;
|
|||
|
||||
namespace android {
|
||||
namespace init {
|
||||
|
||||
class PersistWriteThread;
|
||||
|
||||
constexpr auto FINGERPRINT_PROP = "ro.build.fingerprint";
|
||||
constexpr auto LEGACY_FINGERPRINT_PROP = "ro.build.legacy.fingerprint";
|
||||
constexpr auto ID_PROP = "ro.build.id";
|
||||
|
@ -115,6 +118,8 @@ static bool accept_messages = false;
|
|||
static std::mutex accept_messages_lock;
|
||||
static std::thread property_service_thread;
|
||||
|
||||
static std::unique_ptr<PersistWriteThread> persist_write_thread;
|
||||
|
||||
static PropertyInfoAreaFile property_info_area;
|
||||
|
||||
struct PropertyAuditData {
|
||||
|
@ -177,48 +182,13 @@ static bool CheckMacPerms(const std::string& name, const char* target_context,
|
|||
return has_access;
|
||||
}
|
||||
|
||||
static uint32_t PropertySet(const std::string& name, const std::string& value, std::string* error) {
|
||||
size_t valuelen = value.size();
|
||||
|
||||
if (!IsLegalPropertyName(name)) {
|
||||
*error = "Illegal property name";
|
||||
return PROP_ERROR_INVALID_NAME;
|
||||
}
|
||||
|
||||
if (auto result = IsLegalPropertyValue(name, value); !result.ok()) {
|
||||
*error = result.error().message();
|
||||
return PROP_ERROR_INVALID_VALUE;
|
||||
}
|
||||
|
||||
prop_info* pi = (prop_info*) __system_property_find(name.c_str());
|
||||
if (pi != nullptr) {
|
||||
// ro.* properties are actually "write-once".
|
||||
if (StartsWith(name, "ro.")) {
|
||||
*error = "Read-only property was already set";
|
||||
return PROP_ERROR_READ_ONLY_PROPERTY;
|
||||
}
|
||||
|
||||
__system_property_update(pi, value.c_str(), valuelen);
|
||||
} else {
|
||||
int rc = __system_property_add(name.c_str(), name.size(), value.c_str(), valuelen);
|
||||
if (rc < 0) {
|
||||
*error = "__system_property_add failed";
|
||||
return PROP_ERROR_SET_FAILED;
|
||||
}
|
||||
}
|
||||
|
||||
// Don't write properties to disk until after we have read all default
|
||||
// properties to prevent them from being overwritten by default values.
|
||||
if (persistent_properties_loaded && StartsWith(name, "persist.")) {
|
||||
WritePersistentProperty(name, value);
|
||||
}
|
||||
void NotifyPropertyChange(const std::string& name, const std::string& value) {
|
||||
// If init hasn't started its main loop, then it won't be handling property changed messages
|
||||
// anyway, so there's no need to try to send them.
|
||||
auto lock = std::lock_guard{accept_messages_lock};
|
||||
if (accept_messages) {
|
||||
PropertyChanged(name, value);
|
||||
}
|
||||
return PROP_SUCCESS;
|
||||
}
|
||||
|
||||
class AsyncRestorecon {
|
||||
|
@ -259,7 +229,9 @@ class AsyncRestorecon {
|
|||
|
||||
class SocketConnection {
|
||||
public:
|
||||
SocketConnection() = default;
|
||||
SocketConnection(int socket, const ucred& cred) : socket_(socket), cred_(cred) {}
|
||||
SocketConnection(SocketConnection&&) = default;
|
||||
|
||||
bool RecvUint32(uint32_t* value, uint32_t* timeout_ms) {
|
||||
return RecvFully(value, sizeof(*value), timeout_ms);
|
||||
|
@ -318,6 +290,8 @@ class SocketConnection {
|
|||
|
||||
const ucred& cred() { return cred_; }
|
||||
|
||||
SocketConnection& operator=(SocketConnection&&) = default;
|
||||
|
||||
private:
|
||||
bool PollIn(uint32_t* timeout_ms) {
|
||||
struct pollfd ufd = {
|
||||
|
@ -388,9 +362,78 @@ class SocketConnection {
|
|||
unique_fd socket_;
|
||||
ucred cred_;
|
||||
|
||||
DISALLOW_IMPLICIT_CONSTRUCTORS(SocketConnection);
|
||||
DISALLOW_COPY_AND_ASSIGN(SocketConnection);
|
||||
};
|
||||
|
||||
class PersistWriteThread {
|
||||
public:
|
||||
PersistWriteThread();
|
||||
void Write(std::string name, std::string value, SocketConnection socket);
|
||||
|
||||
private:
|
||||
void Work();
|
||||
|
||||
private:
|
||||
std::thread thread_;
|
||||
std::mutex mutex_;
|
||||
std::condition_variable cv_;
|
||||
std::deque<std::tuple<std::string, std::string, SocketConnection>> work_;
|
||||
};
|
||||
|
||||
static std::optional<uint32_t> PropertySet(const std::string& name, const std::string& value,
|
||||
SocketConnection* socket, std::string* error) {
|
||||
size_t valuelen = value.size();
|
||||
|
||||
if (!IsLegalPropertyName(name)) {
|
||||
*error = "Illegal property name";
|
||||
return {PROP_ERROR_INVALID_NAME};
|
||||
}
|
||||
|
||||
if (auto result = IsLegalPropertyValue(name, value); !result.ok()) {
|
||||
*error = result.error().message();
|
||||
return {PROP_ERROR_INVALID_VALUE};
|
||||
}
|
||||
|
||||
prop_info* pi = (prop_info*)__system_property_find(name.c_str());
|
||||
if (pi != nullptr) {
|
||||
// ro.* properties are actually "write-once".
|
||||
if (StartsWith(name, "ro.")) {
|
||||
*error = "Read-only property was already set";
|
||||
return {PROP_ERROR_READ_ONLY_PROPERTY};
|
||||
}
|
||||
|
||||
__system_property_update(pi, value.c_str(), valuelen);
|
||||
} else {
|
||||
int rc = __system_property_add(name.c_str(), name.size(), value.c_str(), valuelen);
|
||||
if (rc < 0) {
|
||||
*error = "__system_property_add failed";
|
||||
return {PROP_ERROR_SET_FAILED};
|
||||
}
|
||||
}
|
||||
|
||||
// Don't write properties to disk until after we have read all default
|
||||
// properties to prevent them from being overwritten by default values.
|
||||
if (socket && persistent_properties_loaded && StartsWith(name, "persist.")) {
|
||||
if (persist_write_thread) {
|
||||
persist_write_thread->Write(name, value, std::move(*socket));
|
||||
return {};
|
||||
}
|
||||
WritePersistentProperty(name, value);
|
||||
}
|
||||
|
||||
NotifyPropertyChange(name, value);
|
||||
return {PROP_SUCCESS};
|
||||
}
|
||||
|
||||
// Helper for PropertySet, for the case where no socket is used, and therefore an asynchronous
|
||||
// return is not possible.
|
||||
static uint32_t PropertySetNoSocket(const std::string& name, const std::string& value,
|
||||
std::string* error) {
|
||||
auto ret = PropertySet(name, value, nullptr, error);
|
||||
CHECK(ret.has_value());
|
||||
return *ret;
|
||||
}
|
||||
|
||||
static uint32_t SendControlMessage(const std::string& msg, const std::string& name, pid_t pid,
|
||||
SocketConnection* socket, std::string* error) {
|
||||
auto lock = std::lock_guard{accept_messages_lock};
|
||||
|
@ -481,16 +524,17 @@ uint32_t CheckPermissions(const std::string& name, const std::string& value,
|
|||
return PROP_SUCCESS;
|
||||
}
|
||||
|
||||
// This returns one of the enum of PROP_SUCCESS or PROP_ERROR*.
|
||||
uint32_t HandlePropertySet(const std::string& name, const std::string& value,
|
||||
const std::string& source_context, const ucred& cr,
|
||||
SocketConnection* socket, std::string* error) {
|
||||
// This returns one of the enum of PROP_SUCCESS or PROP_ERROR*, or std::nullopt
|
||||
// if asynchronous.
|
||||
std::optional<uint32_t> HandlePropertySet(const std::string& name, const std::string& value,
|
||||
const std::string& source_context, const ucred& cr,
|
||||
SocketConnection* socket, std::string* error) {
|
||||
if (auto ret = CheckPermissions(name, value, source_context, cr, error); ret != PROP_SUCCESS) {
|
||||
return ret;
|
||||
return {ret};
|
||||
}
|
||||
|
||||
if (StartsWith(name, "ctl.")) {
|
||||
return SendControlMessage(name.c_str() + 4, value, cr.pid, socket, error);
|
||||
return {SendControlMessage(name.c_str() + 4, value, cr.pid, socket, error)};
|
||||
}
|
||||
|
||||
// sys.powerctl is a special property that is used to make the device reboot. We want to log
|
||||
|
@ -511,7 +555,7 @@ uint32_t HandlePropertySet(const std::string& name, const std::string& value,
|
|||
}
|
||||
if (value == "reboot,userspace" && !is_userspace_reboot_supported().value_or(false)) {
|
||||
*error = "Userspace reboot is not supported by this device";
|
||||
return PROP_ERROR_INVALID_VALUE;
|
||||
return {PROP_ERROR_INVALID_VALUE};
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -522,10 +566,20 @@ uint32_t HandlePropertySet(const std::string& name, const std::string& value,
|
|||
if (name == kRestoreconProperty && cr.pid != 1 && !value.empty()) {
|
||||
static AsyncRestorecon async_restorecon;
|
||||
async_restorecon.TriggerRestorecon(value);
|
||||
return PROP_SUCCESS;
|
||||
return {PROP_SUCCESS};
|
||||
}
|
||||
|
||||
return PropertySet(name, value, error);
|
||||
return PropertySet(name, value, socket, error);
|
||||
}
|
||||
|
||||
// Helper for HandlePropertySet, for the case where no socket is used, and
|
||||
// therefore an asynchronous return is not possible.
|
||||
uint32_t HandlePropertySetNoSocket(const std::string& name, const std::string& value,
|
||||
const std::string& source_context, const ucred& cr,
|
||||
std::string* error) {
|
||||
auto ret = HandlePropertySet(name, value, source_context, cr, nullptr, error);
|
||||
CHECK(ret.has_value());
|
||||
return *ret;
|
||||
}
|
||||
|
||||
static void handle_property_set_fd() {
|
||||
|
@ -576,8 +630,7 @@ static void handle_property_set_fd() {
|
|||
|
||||
const auto& cr = socket.cred();
|
||||
std::string error;
|
||||
uint32_t result =
|
||||
HandlePropertySet(prop_name, prop_value, source_context, cr, nullptr, &error);
|
||||
auto result = HandlePropertySetNoSocket(prop_name, prop_value, source_context, cr, &error);
|
||||
if (result != PROP_SUCCESS) {
|
||||
LOG(ERROR) << "Unable to set property '" << prop_name << "' from uid:" << cr.uid
|
||||
<< " gid:" << cr.gid << " pid:" << cr.pid << ": " << error;
|
||||
|
@ -603,14 +656,19 @@ static void handle_property_set_fd() {
|
|||
return;
|
||||
}
|
||||
|
||||
// HandlePropertySet takes ownership of the socket if the set is handled asynchronously.
|
||||
const auto& cr = socket.cred();
|
||||
std::string error;
|
||||
uint32_t result = HandlePropertySet(name, value, source_context, cr, &socket, &error);
|
||||
if (result != PROP_SUCCESS) {
|
||||
auto result = HandlePropertySet(name, value, source_context, cr, &socket, &error);
|
||||
if (!result) {
|
||||
// Result will be sent after completion.
|
||||
return;
|
||||
}
|
||||
if (*result != PROP_SUCCESS) {
|
||||
LOG(ERROR) << "Unable to set property '" << name << "' from uid:" << cr.uid
|
||||
<< " gid:" << cr.gid << " pid:" << cr.pid << ": " << error;
|
||||
}
|
||||
socket.SendUint32(result);
|
||||
socket.SendUint32(*result);
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -622,10 +680,9 @@ static void handle_property_set_fd() {
|
|||
}
|
||||
|
||||
uint32_t InitPropertySet(const std::string& name, const std::string& value) {
|
||||
uint32_t result = 0;
|
||||
ucred cr = {.pid = 1, .uid = 0, .gid = 0};
|
||||
std::string error;
|
||||
result = HandlePropertySet(name, value, kInitContext, cr, nullptr, &error);
|
||||
auto result = HandlePropertySetNoSocket(name, value, kInitContext, cr, &error);
|
||||
if (result != PROP_SUCCESS) {
|
||||
LOG(ERROR) << "Init cannot set '" << name << "' to '" << value << "': " << error;
|
||||
}
|
||||
|
@ -795,7 +852,7 @@ static void load_override_properties() {
|
|||
load_properties_from_file("/data/local.prop", nullptr, &properties);
|
||||
for (const auto& [name, value] : properties) {
|
||||
std::string error;
|
||||
if (PropertySet(name, value, &error) != PROP_SUCCESS) {
|
||||
if (PropertySetNoSocket(name, value, &error) != PROP_SUCCESS) {
|
||||
LOG(ERROR) << "Could not set '" << name << "' to '" << value
|
||||
<< "' in /data/local.prop: " << error;
|
||||
}
|
||||
|
@ -861,7 +918,7 @@ static void property_initialize_ro_product_props() {
|
|||
LOG(INFO) << "Setting product property " << base_prop << " to '" << target_prop_val
|
||||
<< "' (from " << target_prop << ")";
|
||||
std::string error;
|
||||
uint32_t res = PropertySet(base_prop, target_prop_val, &error);
|
||||
auto res = PropertySetNoSocket(base_prop, target_prop_val, &error);
|
||||
if (res != PROP_SUCCESS) {
|
||||
LOG(ERROR) << "Error setting product property " << base_prop << ": err=" << res
|
||||
<< " (" << error << ")";
|
||||
|
@ -890,7 +947,7 @@ static void property_initialize_build_id() {
|
|||
}
|
||||
|
||||
std::string error;
|
||||
auto res = PropertySet(ID_PROP, build_id, &error);
|
||||
auto res = PropertySetNoSocket(ID_PROP, build_id, &error);
|
||||
if (res != PROP_SUCCESS) {
|
||||
LOG(ERROR) << "Failed to set " << ID_PROP << " to " << build_id;
|
||||
}
|
||||
|
@ -938,7 +995,7 @@ static void property_derive_legacy_build_fingerprint() {
|
|||
<< legacy_build_fingerprint << "'";
|
||||
|
||||
std::string error;
|
||||
uint32_t res = PropertySet(LEGACY_FINGERPRINT_PROP, legacy_build_fingerprint, &error);
|
||||
auto res = PropertySetNoSocket(LEGACY_FINGERPRINT_PROP, legacy_build_fingerprint, &error);
|
||||
if (res != PROP_SUCCESS) {
|
||||
LOG(ERROR) << "Error setting property '" << LEGACY_FINGERPRINT_PROP << "': err=" << res
|
||||
<< " (" << error << ")";
|
||||
|
@ -956,7 +1013,7 @@ static void property_derive_build_fingerprint() {
|
|||
LOG(INFO) << "Setting property '" << FINGERPRINT_PROP << "' to '" << build_fingerprint << "'";
|
||||
|
||||
std::string error;
|
||||
uint32_t res = PropertySet(FINGERPRINT_PROP, build_fingerprint, &error);
|
||||
auto res = PropertySetNoSocket(FINGERPRINT_PROP, build_fingerprint, &error);
|
||||
if (res != PROP_SUCCESS) {
|
||||
LOG(ERROR) << "Error setting property '" << FINGERPRINT_PROP << "': err=" << res << " ("
|
||||
<< error << ")";
|
||||
|
@ -976,7 +1033,7 @@ static void property_derive_build_product() {
|
|||
LOG(INFO) << "Setting property 'ro.build.product' to '" << build_product << "'";
|
||||
|
||||
std::string error;
|
||||
uint32_t res = PropertySet("ro.build.product", build_product, &error);
|
||||
auto res = PropertySetNoSocket("ro.build.product", build_product, &error);
|
||||
if (res != PROP_SUCCESS) {
|
||||
LOG(ERROR) << "Error setting property 'ro.build.product': err=" << res << " (" << error
|
||||
<< ")";
|
||||
|
@ -1006,7 +1063,7 @@ static void property_derive_build_description() {
|
|||
LOG(INFO) << "Setting property 'ro.build.description' to '" << build_description << "'";
|
||||
|
||||
std::string error;
|
||||
uint32_t res = PropertySet("ro.build.description", build_description, &error);
|
||||
auto res = PropertySetNoSocket("ro.build.description", build_description, &error);
|
||||
if (res != PROP_SUCCESS) {
|
||||
LOG(ERROR) << "Error setting property 'ro.build.description': err=" << res << " (" << error
|
||||
<< ")";
|
||||
|
@ -1052,7 +1109,7 @@ static void property_derive_build_display_id() {
|
|||
LOG(INFO) << "Setting property 'ro.build.display.id' to '" << build_display_id << "'";
|
||||
|
||||
std::string error;
|
||||
uint32_t res = PropertySet("ro.build.display.id", build_display_id, &error);
|
||||
auto res = PropertySetNoSocket("ro.build.display.id", build_display_id, &error);
|
||||
if (res != PROP_SUCCESS) {
|
||||
LOG(ERROR) << "Error setting property 'ro.build.display.id': err=" << res << " (" << error
|
||||
<< ")";
|
||||
|
@ -1121,7 +1178,7 @@ static void property_initialize_ro_cpu_abilist() {
|
|||
LOG(INFO) << "Setting property '" << prop << "' to '" << prop_val << "'";
|
||||
|
||||
std::string error;
|
||||
uint32_t res = PropertySet(prop, prop_val, &error);
|
||||
auto res = PropertySetNoSocket(prop, prop_val, &error);
|
||||
if (res != PROP_SUCCESS) {
|
||||
LOG(ERROR) << "Error setting property '" << prop << "': err=" << res << " (" << error
|
||||
<< ")";
|
||||
|
@ -1155,7 +1212,7 @@ static void property_initialize_ro_vendor_api_level() {
|
|||
int api_level = std::min(read_api_level_props(BOARD_API_LEVEL_PROPS),
|
||||
read_api_level_props(DEVICE_API_LEVEL_PROPS));
|
||||
std::string error;
|
||||
uint32_t res = PropertySet(VENDOR_API_LEVEL_PROP, std::to_string(api_level), &error);
|
||||
auto res = PropertySetNoSocket(VENDOR_API_LEVEL_PROP, std::to_string(api_level), &error);
|
||||
if (res != PROP_SUCCESS) {
|
||||
LOG(ERROR) << "Failed to set " << VENDOR_API_LEVEL_PROP << " with " << api_level << ": "
|
||||
<< error << "(" << res << ")";
|
||||
|
@ -1249,7 +1306,7 @@ void PropertyLoadBootDefaults() {
|
|||
|
||||
for (const auto& [name, value] : properties) {
|
||||
std::string error;
|
||||
if (PropertySet(name, value, &error) != PROP_SUCCESS) {
|
||||
if (PropertySetNoSocket(name, value, &error) != PROP_SUCCESS) {
|
||||
LOG(ERROR) << "Could not set '" << name << "' to '" << value
|
||||
<< "' while loading .prop files" << error;
|
||||
}
|
||||
|
@ -1491,6 +1548,46 @@ static void PropertyServiceThread() {
|
|||
}
|
||||
}
|
||||
|
||||
PersistWriteThread::PersistWriteThread() {
|
||||
auto new_thread = std::thread([this]() -> void { Work(); });
|
||||
thread_.swap(new_thread);
|
||||
}
|
||||
|
||||
void PersistWriteThread::Work() {
|
||||
while (true) {
|
||||
std::tuple<std::string, std::string, SocketConnection> item;
|
||||
|
||||
// Grab the next item within the lock.
|
||||
{
|
||||
std::unique_lock<std::mutex> lock(mutex_);
|
||||
|
||||
while (work_.empty()) {
|
||||
cv_.wait(lock);
|
||||
}
|
||||
|
||||
item = std::move(work_.front());
|
||||
work_.pop_front();
|
||||
}
|
||||
|
||||
std::this_thread::sleep_for(1s);
|
||||
|
||||
// Perform write/fsync outside the lock.
|
||||
WritePersistentProperty(std::get<0>(item), std::get<1>(item));
|
||||
NotifyPropertyChange(std::get<0>(item), std::get<1>(item));
|
||||
|
||||
SocketConnection& socket = std::get<2>(item);
|
||||
socket.SendUint32(PROP_SUCCESS);
|
||||
}
|
||||
}
|
||||
|
||||
void PersistWriteThread::Write(std::string name, std::string value, SocketConnection socket) {
|
||||
{
|
||||
std::unique_lock<std::mutex> lock(mutex_);
|
||||
work_.emplace_back(std::move(name), std::move(value), std::move(socket));
|
||||
}
|
||||
cv_.notify_all();
|
||||
}
|
||||
|
||||
void StartPropertyService(int* epoll_socket) {
|
||||
InitPropertySet("ro.property_service.version", "2");
|
||||
|
||||
|
@ -1515,6 +1612,13 @@ void StartPropertyService(int* epoll_socket) {
|
|||
|
||||
auto new_thread = std::thread{PropertyServiceThread};
|
||||
property_service_thread.swap(new_thread);
|
||||
|
||||
auto async_persist_writes =
|
||||
android::base::GetBoolProperty("ro.property_service.async_persist_writes", false);
|
||||
|
||||
if (async_persist_writes) {
|
||||
persist_write_thread = std::make_unique<PersistWriteThread>();
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace init
|
||||
|
|
|
@ -18,7 +18,11 @@
|
|||
|
||||
#include <sys/socket.h>
|
||||
|
||||
#include <condition_variable>
|
||||
#include <deque>
|
||||
#include <mutex>
|
||||
#include <string>
|
||||
#include <thread>
|
||||
|
||||
#include "epoll.h"
|
||||
|
||||
|
|
|
@ -112,6 +112,10 @@ void LaunchFirstStageSnapuserd(SnapshotDriver driver) {
|
|||
|
||||
setenv(kSnapuserdFirstStagePidVar, std::to_string(pid).c_str(), 1);
|
||||
|
||||
if (!client->RemoveTransitionedDaemonIndicator()) {
|
||||
LOG(ERROR) << "RemoveTransitionedDaemonIndicator failed";
|
||||
}
|
||||
|
||||
LOG(INFO) << "Relaunched snapuserd with pid: " << pid;
|
||||
}
|
||||
|
||||
|
@ -263,6 +267,19 @@ void SnapuserdSelinuxHelper::FinishTransition() {
|
|||
* we may see audit logs.
|
||||
*/
|
||||
bool SnapuserdSelinuxHelper::TestSnapuserdIsReady() {
|
||||
// Wait for the daemon to be fully up. Daemon will write to path
|
||||
// /metadata/ota/daemon-alive-indicator only when all the threads
|
||||
// are ready and attached to dm-user.
|
||||
//
|
||||
// This check will fail for GRF devices with vendor on Android S.
|
||||
// snapuserd binary from Android S won't be able to communicate
|
||||
// and hence, we will fallback and issue I/O to verify
|
||||
// the presence of daemon.
|
||||
auto client = std::make_unique<SnapuserdClient>();
|
||||
if (!client->IsTransitionedDaemonReady()) {
|
||||
LOG(ERROR) << "IsTransitionedDaemonReady failed";
|
||||
}
|
||||
|
||||
std::string dev = "/dev/block/mapper/system"s + fs_mgr_get_slot_suffix();
|
||||
android::base::unique_fd fd(open(dev.c_str(), O_RDONLY | O_DIRECT));
|
||||
if (fd < 0) {
|
||||
|
|
|
@ -8,5 +8,10 @@
|
|||
{
|
||||
"name": "libcutils_test"
|
||||
}
|
||||
],
|
||||
"kernel-presubmit": [
|
||||
{
|
||||
"name": "libcutils_test"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
|
@ -0,0 +1,17 @@
|
|||
BasedOnStyle: Google
|
||||
AllowShortIfStatementsOnASingleLine: true
|
||||
AllowShortFunctionsOnASingleLine: false
|
||||
AllowShortLoopsOnASingleLine: true
|
||||
BinPackArguments: true
|
||||
BinPackParameters: true
|
||||
ColumnLimit: 100
|
||||
CommentPragmas: NOLINT:.*
|
||||
ContinuationIndentWidth: 8
|
||||
DerivePointerAlignment: false
|
||||
IndentWidth: 4
|
||||
PointerAlignment: Left
|
||||
TabWidth: 4
|
||||
AccessModifierOffset: -4
|
||||
IncludeCategories:
|
||||
- Regex: '^"Log\.h"'
|
||||
Priority: -1
|
|
@ -0,0 +1,71 @@
|
|||
|
||||
//
|
||||
// Copyright (C) 2023 The Android Open Source Project
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
package {
|
||||
default_applicable_licenses: ["Android-Apache-2.0"],
|
||||
}
|
||||
|
||||
cc_library {
|
||||
name: "libexpresslog",
|
||||
srcs: [
|
||||
"Counter.cpp",
|
||||
],
|
||||
cflags: [
|
||||
"-DNAMESPACE_FOR_HASH_FUNCTIONS=farmhash",
|
||||
"-Wall",
|
||||
"-Werror",
|
||||
],
|
||||
header_libs: [
|
||||
"libtextclassifier_hash_headers",
|
||||
],
|
||||
static_libs: [
|
||||
"libstatslog_express",
|
||||
"libtextclassifier_hash_static",
|
||||
],
|
||||
shared_libs: [
|
||||
"libbase",
|
||||
"libstatssocket",
|
||||
],
|
||||
export_include_dirs: ["include"],
|
||||
}
|
||||
|
||||
genrule {
|
||||
name: "statslog_express.h",
|
||||
tools: ["stats-log-api-gen"],
|
||||
cmd: "$(location stats-log-api-gen) --header $(genDir)/statslog_express.h --module expresslog --namespace android,expresslog",
|
||||
out: [
|
||||
"statslog_express.h",
|
||||
],
|
||||
}
|
||||
|
||||
genrule {
|
||||
name: "statslog_express.cpp",
|
||||
tools: ["stats-log-api-gen"],
|
||||
cmd: "$(location stats-log-api-gen) --cpp $(genDir)/statslog_express.cpp --module expresslog --namespace android,expresslog --importHeader statslog_express.h",
|
||||
out: [
|
||||
"statslog_express.cpp",
|
||||
],
|
||||
}
|
||||
|
||||
cc_library_static {
|
||||
name: "libstatslog_express",
|
||||
generated_sources: ["statslog_express.cpp"],
|
||||
generated_headers: ["statslog_express.h"],
|
||||
export_generated_headers: ["statslog_express.h"],
|
||||
shared_libs: [
|
||||
"libstatssocket",
|
||||
],
|
||||
}
|
|
@ -0,0 +1,32 @@
|
|||
//
|
||||
// Copyright (C) 2023 The Android Open Source Project
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
#include "include/Counter.h"
|
||||
|
||||
#include <statslog_express.h>
|
||||
#include <string.h>
|
||||
#include <utils/hash/farmhash.h>
|
||||
|
||||
namespace android {
|
||||
namespace expresslog {
|
||||
|
||||
void Counter::logIncrement(const char* metricName, int64_t amount) {
|
||||
const int64_t metricIdHash = farmhash::Fingerprint64(metricName, strlen(metricName));
|
||||
stats_write(EXPRESS_EVENT_REPORTED, metricIdHash, amount);
|
||||
}
|
||||
|
||||
} // namespace expresslog
|
||||
} // namespace android
|
|
@ -0,0 +1,30 @@
|
|||
//
|
||||
// Copyright (C) 2023 The Android Open Source Project
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
#pragma once
|
||||
#include <stdint.h>
|
||||
|
||||
namespace android {
|
||||
namespace expresslog {
|
||||
|
||||
/** Counter encapsulates StatsD write API calls */
|
||||
class Counter final {
|
||||
public:
|
||||
static void logIncrement(const char* metricId, int64_t amount = 1);
|
||||
};
|
||||
|
||||
} // namespace expresslog
|
||||
} // namespace android
|
|
@ -1,20 +1,18 @@
|
|||
|
||||
#include <ctype.h>
|
||||
#include <dirent.h>
|
||||
#include <err.h>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <getopt.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/sysmacros.h>
|
||||
#include <dirent.h>
|
||||
|
||||
#include <stdarg.h>
|
||||
#include <fcntl.h>
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <linux/kdev_t.h>
|
||||
|
||||
|
@ -23,23 +21,12 @@
|
|||
|
||||
/* NOTES
|
||||
**
|
||||
** - see buffer-format.txt from the linux kernel docs for
|
||||
** an explanation of this file format
|
||||
** - see https://www.kernel.org/doc/Documentation/early-userspace/buffer-format.txt
|
||||
** for an explanation of this file format
|
||||
** - dotfiles are ignored
|
||||
** - directories named 'root' are ignored
|
||||
*/
|
||||
|
||||
static void die(const char* why, ...) {
|
||||
va_list ap;
|
||||
|
||||
va_start(ap, why);
|
||||
fprintf(stderr,"error: ");
|
||||
vfprintf(stderr, why, ap);
|
||||
fprintf(stderr,"\n");
|
||||
va_end(ap);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
struct fs_config_entry {
|
||||
char* name;
|
||||
int uid, gid, mode;
|
||||
|
@ -48,17 +35,8 @@ struct fs_config_entry {
|
|||
static struct fs_config_entry* canned_config = NULL;
|
||||
static const char* target_out_path = NULL;
|
||||
|
||||
/* Each line in the canned file should be a path plus three ints (uid,
|
||||
* gid, mode). */
|
||||
#ifdef PATH_MAX
|
||||
#define CANNED_LINE_LENGTH (PATH_MAX+100)
|
||||
#else
|
||||
#define CANNED_LINE_LENGTH (1024)
|
||||
#endif
|
||||
|
||||
#define TRAILER "TRAILER!!!"
|
||||
|
||||
static int verbose = 0;
|
||||
static int total_size = 0;
|
||||
|
||||
static void fix_stat(const char *path, struct stat *s)
|
||||
|
@ -134,7 +112,7 @@ static void _eject(struct stat *s, char *out, int olen, char *data, unsigned dat
|
|||
|
||||
total_size += 6 + 8*13 + olen + 1;
|
||||
|
||||
if(strlen(out) != (unsigned int)olen) die("ACK!");
|
||||
if(strlen(out) != (unsigned int)olen) errx(1, "ACK!");
|
||||
|
||||
while(total_size & 3) {
|
||||
total_size++;
|
||||
|
@ -168,23 +146,16 @@ static int compare(const void* a, const void* b) {
|
|||
static void _archive_dir(char *in, char *out, int ilen, int olen)
|
||||
{
|
||||
int i, t;
|
||||
DIR *d;
|
||||
struct dirent *de;
|
||||
|
||||
if(verbose) {
|
||||
fprintf(stderr,"_archive_dir('%s','%s',%d,%d)\n",
|
||||
in, out, ilen, olen);
|
||||
}
|
||||
|
||||
d = opendir(in);
|
||||
if(d == 0) die("cannot open directory '%s'", in);
|
||||
DIR* d = opendir(in);
|
||||
if (d == NULL) err(1, "cannot open directory '%s'", in);
|
||||
|
||||
int size = 32;
|
||||
int entries = 0;
|
||||
char** names = malloc(size * sizeof(char*));
|
||||
if (names == NULL) {
|
||||
fprintf(stderr, "failed to allocate dir names array (size %d)\n", size);
|
||||
exit(1);
|
||||
errx(1, "failed to allocate dir names array (size %d)", size);
|
||||
}
|
||||
|
||||
while((de = readdir(d)) != 0){
|
||||
|
@ -198,16 +169,12 @@ static void _archive_dir(char *in, char *out, int ilen, int olen)
|
|||
size *= 2;
|
||||
names = realloc(names, size * sizeof(char*));
|
||||
if (names == NULL) {
|
||||
fprintf(stderr, "failed to reallocate dir names array (size %d)\n",
|
||||
size);
|
||||
exit(1);
|
||||
errx(1, "failed to reallocate dir names array (size %d)", size);
|
||||
}
|
||||
}
|
||||
names[entries] = strdup(de->d_name);
|
||||
if (names[entries] == NULL) {
|
||||
fprintf(stderr, "failed to strdup name \"%s\"\n",
|
||||
de->d_name);
|
||||
exit(1);
|
||||
errx(1, "failed to strdup name \"%s\"", de->d_name);
|
||||
}
|
||||
++entries;
|
||||
}
|
||||
|
@ -241,26 +208,17 @@ static void _archive_dir(char *in, char *out, int ilen, int olen)
|
|||
static void _archive(char *in, char *out, int ilen, int olen)
|
||||
{
|
||||
struct stat s;
|
||||
|
||||
if(verbose) {
|
||||
fprintf(stderr,"_archive('%s','%s',%d,%d)\n",
|
||||
in, out, ilen, olen);
|
||||
}
|
||||
|
||||
if(lstat(in, &s)) die("could not stat '%s'\n", in);
|
||||
if(lstat(in, &s)) err(1, "could not stat '%s'", in);
|
||||
|
||||
if(S_ISREG(s.st_mode)){
|
||||
char *tmp;
|
||||
int fd;
|
||||
int fd = open(in, O_RDONLY);
|
||||
if(fd < 0) err(1, "cannot open '%s' for read", in);
|
||||
|
||||
fd = open(in, O_RDONLY);
|
||||
if(fd < 0) die("cannot open '%s' for read", in);
|
||||
|
||||
tmp = (char*) malloc(s.st_size);
|
||||
if(tmp == 0) die("cannot allocate %d bytes", s.st_size);
|
||||
char* tmp = (char*) malloc(s.st_size);
|
||||
if(tmp == 0) errx(1, "cannot allocate %zd bytes", s.st_size);
|
||||
|
||||
if(read(fd, tmp, s.st_size) != s.st_size) {
|
||||
die("cannot read %d bytes", s.st_size);
|
||||
err(1, "cannot read %zd bytes", s.st_size);
|
||||
}
|
||||
|
||||
_eject(&s, out, olen, tmp, s.st_size);
|
||||
|
@ -274,13 +232,13 @@ static void _archive(char *in, char *out, int ilen, int olen)
|
|||
char buf[1024];
|
||||
int size;
|
||||
size = readlink(in, buf, 1024);
|
||||
if(size < 0) die("cannot read symlink '%s'", in);
|
||||
if(size < 0) err(1, "cannot read symlink '%s'", in);
|
||||
_eject(&s, out, olen, buf, size);
|
||||
} else if(S_ISBLK(s.st_mode) || S_ISCHR(s.st_mode) ||
|
||||
S_ISFIFO(s.st_mode) || S_ISSOCK(s.st_mode)) {
|
||||
_eject(&s, out, olen, NULL, 0);
|
||||
} else {
|
||||
die("Unknown '%s' (mode %d)?\n", in, s.st_mode);
|
||||
errx(1, "Unknown '%s' (mode %d)?", in, s.st_mode);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -302,17 +260,18 @@ static void read_canned_config(char* filename)
|
|||
canned_config =
|
||||
(struct fs_config_entry*)malloc(allocated * sizeof(struct fs_config_entry));
|
||||
|
||||
char line[CANNED_LINE_LENGTH];
|
||||
FILE* f = fopen(filename, "r");
|
||||
if (f == NULL) die("failed to open canned file '%s'", filename);
|
||||
FILE* fp = fopen(filename, "r");
|
||||
if (fp == NULL) err(1, "failed to open canned file '%s'", filename);
|
||||
|
||||
while (fgets(line, CANNED_LINE_LENGTH, f) != NULL) {
|
||||
char* line = NULL;
|
||||
size_t allocated_len;
|
||||
while (getline(&line, &allocated_len, fp) != -1) {
|
||||
if (!line[0]) break;
|
||||
if (used >= allocated) {
|
||||
allocated *= 2;
|
||||
canned_config = (struct fs_config_entry*)realloc(
|
||||
canned_config, allocated * sizeof(struct fs_config_entry));
|
||||
if (canned_config == NULL) die("failed to reallocate memory");
|
||||
if (canned_config == NULL) errx(1, "failed to reallocate memory");
|
||||
}
|
||||
|
||||
struct fs_config_entry* cc = canned_config + used;
|
||||
|
@ -332,17 +291,18 @@ static void read_canned_config(char* filename)
|
|||
++allocated;
|
||||
canned_config = (struct fs_config_entry*)realloc(
|
||||
canned_config, allocated * sizeof(struct fs_config_entry));
|
||||
if (canned_config == NULL) die("failed to reallocate memory");
|
||||
if (canned_config == NULL) errx(1, "failed to reallocate memory");
|
||||
}
|
||||
canned_config[used].name = NULL;
|
||||
|
||||
fclose(f);
|
||||
free(line);
|
||||
fclose(fp);
|
||||
}
|
||||
|
||||
static void devnodes_desc_error(const char* filename, unsigned long line_num,
|
||||
const char* msg)
|
||||
{
|
||||
errx(EXIT_FAILURE, "failed to read nodes desc file '%s' line %lu: %s", filename, line_num, msg);
|
||||
errx(1, "failed to read nodes desc file '%s' line %lu: %s", filename, line_num, msg);
|
||||
}
|
||||
|
||||
static int append_devnodes_desc_dir(char* path, char* args)
|
||||
|
@ -386,15 +346,15 @@ static int append_devnodes_desc_nod(char* path, char* args)
|
|||
|
||||
static void append_devnodes_desc(const char* filename)
|
||||
{
|
||||
FILE* f = fopen(filename, "re");
|
||||
if (!f) err(EXIT_FAILURE, "failed to open nodes description file '%s'", filename);
|
||||
FILE* fp = fopen(filename, "re");
|
||||
if (!fp) err(1, "failed to open nodes description file '%s'", filename);
|
||||
|
||||
char *line, *args, *type, *path;
|
||||
unsigned long line_num = 0;
|
||||
size_t allocated_len;
|
||||
|
||||
while (getline(&line, &allocated_len, f) != -1) {
|
||||
char* type;
|
||||
char* line = NULL;
|
||||
size_t allocated_len;
|
||||
while (getline(&line, &allocated_len, fp) != -1) {
|
||||
char *type, *path, *args;
|
||||
|
||||
line_num++;
|
||||
|
||||
|
@ -428,7 +388,7 @@ static void append_devnodes_desc(const char* filename)
|
|||
}
|
||||
|
||||
free(line);
|
||||
fclose(f);
|
||||
fclose(fp);
|
||||
}
|
||||
|
||||
static const struct option long_options[] = {
|
||||
|
@ -448,7 +408,8 @@ static void usage(void)
|
|||
"\t-f, --file=FILE: Canned configuration file\n"
|
||||
"\t-h, --help: Print this help\n"
|
||||
"\t-n, --nodes=FILE: Dev nodes description file\n"
|
||||
"\nDev nodes description:\n"
|
||||
"\n"
|
||||
"Dev nodes description:\n"
|
||||
"\t[dir|nod] [perms] [uid] [gid] [c|b] [minor] [major]\n"
|
||||
"\tExample:\n"
|
||||
"\t\t# My device nodes\n"
|
||||
|
@ -477,7 +438,7 @@ int main(int argc, char *argv[])
|
|||
break;
|
||||
default:
|
||||
usage();
|
||||
die("Unknown option %s", argv[optind - 1]);
|
||||
errx(1, "Unknown option %s", argv[optind - 1]);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -486,7 +447,7 @@ int main(int argc, char *argv[])
|
|||
|
||||
if (num_dirs <= 0) {
|
||||
usage();
|
||||
die("no directories to process?!");
|
||||
errx(1, "no directories to process?!");
|
||||
}
|
||||
|
||||
while(num_dirs-- > 0){
|
||||
|
|
|
@ -660,7 +660,7 @@ on late-fs
|
|||
chmod 0755 /sys/kernel/tracing
|
||||
chmod 0755 /sys/kernel/debug/tracing
|
||||
|
||||
# HALs required before storage encryption can get unlocked (FBE/FDE)
|
||||
# HALs required before storage encryption can get unlocked (FBE)
|
||||
class_start early_hal
|
||||
|
||||
# Load trusted keys from dm-verity protected partitions
|
||||
|
@ -763,9 +763,8 @@ on post-fs-data
|
|||
|
||||
# /data/apex is now available. Start apexd to scan and activate APEXes.
|
||||
#
|
||||
# To handle userspace reboots as well as devices that use FDE, make sure
|
||||
# that apexd is started cleanly here (set apexd.status="") and that it is
|
||||
# restarted if it's already running.
|
||||
# To handle userspace reboots, make sure that apexd is started cleanly here
|
||||
# (set apexd.status="") and that it is restarted if it's already running.
|
||||
#
|
||||
# /data/apex uses encryption=None because direct I/O support is needed on
|
||||
# APEX files, but some devices don't support direct I/O on encrypted files.
|
||||
|
@ -1303,6 +1302,7 @@ service console /system/bin/sh
|
|||
group shell log readproc
|
||||
seclabel u:r:shell:s0
|
||||
setenv HOSTNAME console
|
||||
shutdown critical
|
||||
|
||||
on property:ro.debuggable=1
|
||||
# Give writes to anyone for the trace folder on debug builds.
|
||||
|
|
Loading…
Reference in New Issue