Merge "storageproxyd: Sync parent dir when creating a file"
diff --git a/fs_mgr/libsnapshot/snapuserd/snapuserd_daemon.cpp b/fs_mgr/libsnapshot/snapuserd/snapuserd_daemon.cpp
index ddb1f79..a082742 100644
--- a/fs_mgr/libsnapshot/snapuserd/snapuserd_daemon.cpp
+++ b/fs_mgr/libsnapshot/snapuserd/snapuserd_daemon.cpp
@@ -209,6 +209,8 @@
int main(int argc, char** argv) {
android::base::InitLogging(argv, &android::base::KernelLogger);
+ LOG(INFO) << "snapuserd daemon about to start";
+
android::snapshot::Daemon& daemon = android::snapshot::Daemon::Instance();
if (!daemon.StartDaemon(argc, argv)) {
diff --git a/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_server.cpp b/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_server.cpp
index a79e3e1..eb64704 100644
--- a/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_server.cpp
+++ b/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_server.cpp
@@ -599,8 +599,13 @@
return false;
}
- // We must re-initialize property service access, since we launched before
- // second-stage init.
+ // This initialization of system property is important. When daemon is
+ // launched post selinux transition (before init second stage),
+ // bionic libc initializes system property as part of __libc_init_common();
+ // however that initialization fails silently given that fact that we don't
+ // have /dev/__properties__ setup which is created at init second stage.
+ //
+ // At this point, we have the handlers setup and is safe to setup property.
__system_properties_init();
if (!android::base::WaitForProperty("snapuserd.proxy_ready", "true")) {
diff --git a/healthd/BatteryMonitor.cpp b/healthd/BatteryMonitor.cpp
index 377acb7..5890f9a 100644
--- a/healthd/BatteryMonitor.cpp
+++ b/healthd/BatteryMonitor.cpp
@@ -92,6 +92,7 @@
mBatteryDevicePresent(false),
mBatteryFixedCapacity(0),
mBatteryFixedTemperature(0),
+ mChargerDockOnline(false),
mHealthInfo(std::make_unique<HealthInfo_2_1>()) {
initHealthInfo(mHealthInfo.get());
}
@@ -196,6 +197,7 @@
{"USB_PD", ANDROID_POWER_SUPPLY_TYPE_AC},
{"USB_PD_DRP", ANDROID_POWER_SUPPLY_TYPE_USB},
{"Wireless", ANDROID_POWER_SUPPLY_TYPE_WIRELESS},
+ {"Dock", ANDROID_POWER_SUPPLY_TYPE_DOCK},
{NULL, 0},
};
std::string buf;
@@ -319,9 +321,21 @@
case ANDROID_POWER_SUPPLY_TYPE_WIRELESS:
props.chargerWirelessOnline = true;
break;
+ case ANDROID_POWER_SUPPLY_TYPE_DOCK:
+ mChargerDockOnline = true;
+ break;
default:
- KLOG_WARNING(LOG_TAG, "%s: Unknown power supply type\n",
- mChargerNames[i].string());
+ path.clear();
+ path.appendFormat("%s/%s/is_dock", POWER_SUPPLY_SYSFS_PATH,
+ mChargerNames[i].string());
+ if (access(path.string(), R_OK) == 0) {
+ mChargerDockOnline = true;
+ KLOG_INFO(LOG_TAG, "%s: online\n",
+ mChargerNames[i].string());
+ } else {
+ KLOG_WARNING(LOG_TAG, "%s: Unknown power supply type\n",
+ mChargerNames[i].string());
+ }
}
path.clear();
path.appendFormat("%s/%s/current_max", POWER_SUPPLY_SYSFS_PATH,
@@ -391,8 +405,8 @@
bool BatteryMonitor::isChargerOnline() {
const HealthInfo_1_0& props = mHealthInfo->legacy.legacy;
- return props.chargerAcOnline | props.chargerUsbOnline |
- props.chargerWirelessOnline;
+ return props.chargerAcOnline | props.chargerUsbOnline | props.chargerWirelessOnline |
+ mChargerDockOnline;
}
int BatteryMonitor::getChargeStatus() {
@@ -477,10 +491,10 @@
char vs[128];
const HealthInfo_1_0& props = mHealthInfo->legacy.legacy;
- snprintf(vs, sizeof(vs), "ac: %d usb: %d wireless: %d current_max: %d voltage_max: %d\n",
- props.chargerAcOnline, props.chargerUsbOnline,
- props.chargerWirelessOnline, props.maxChargingCurrent,
- props.maxChargingVoltage);
+ snprintf(vs, sizeof(vs),
+ "ac: %d usb: %d wireless: %d dock: %d current_max: %d voltage_max: %d\n",
+ props.chargerAcOnline, props.chargerUsbOnline, props.chargerWirelessOnline,
+ mChargerDockOnline, props.maxChargingCurrent, props.maxChargingVoltage);
write(fd, vs, strlen(vs));
snprintf(vs, sizeof(vs), "status: %d health: %d present: %d\n",
props.batteryStatus, props.batteryHealth, props.batteryPresent);
@@ -554,6 +568,7 @@
case ANDROID_POWER_SUPPLY_TYPE_AC:
case ANDROID_POWER_SUPPLY_TYPE_USB:
case ANDROID_POWER_SUPPLY_TYPE_WIRELESS:
+ case ANDROID_POWER_SUPPLY_TYPE_DOCK:
path.clear();
path.appendFormat("%s/%s/online", POWER_SUPPLY_SYSFS_PATH, name);
if (access(path.string(), R_OK) == 0)
@@ -691,6 +706,17 @@
case ANDROID_POWER_SUPPLY_TYPE_UNKNOWN:
break;
}
+
+ // Look for "is_dock" file
+ path.clear();
+ path.appendFormat("%s/%s/is_dock", POWER_SUPPLY_SYSFS_PATH, name);
+ if (access(path.string(), R_OK) == 0) {
+ path.clear();
+ path.appendFormat("%s/%s/online", POWER_SUPPLY_SYSFS_PATH, name);
+ if (access(path.string(), R_OK) == 0)
+ mChargerNames.add(String8(name));
+
+ }
}
}
diff --git a/healthd/healthd_draw.cpp b/healthd/healthd_draw.cpp
index 4484fa6..3e73fcd 100644
--- a/healthd/healthd_draw.cpp
+++ b/healthd/healthd_draw.cpp
@@ -94,9 +94,18 @@
gr_flip();
}
-void HealthdDraw::blank_screen(bool blank) {
+void HealthdDraw::blank_screen(bool blank, int drm) {
if (!graphics_available) return;
- gr_fb_blank(blank);
+ gr_fb_blank(blank, drm);
+}
+
+/* support screen rotation for foldable phone */
+void HealthdDraw::rotate_screen(int drm) {
+ if (!graphics_available) return;
+ if (drm == 0)
+ gr_rotate(GRRotation::RIGHT /* landscape mode */);
+ else
+ gr_rotate(GRRotation::NONE /* Portrait mode */);
}
void HealthdDraw::clear_screen(void) {
@@ -139,6 +148,8 @@
void HealthdDraw::determine_xy(const animation::text_field& field,
const int length, int* x, int* y) {
*x = field.pos_x;
+ screen_width_ = gr_fb_width() / (kSplitScreen ? 2 : 1);
+ screen_height_ = gr_fb_height();
int str_len_px = length * field.font->char_width;
if (field.pos_x == CENTER_VAL) {
diff --git a/healthd/healthd_draw.h b/healthd/healthd_draw.h
index 0b48ce8..3d4abbd 100644
--- a/healthd/healthd_draw.h
+++ b/healthd/healthd_draw.h
@@ -31,8 +31,12 @@
// Redraws screen.
void redraw_screen(const animation* batt_anim, GRSurface* surf_unknown);
+ // According to the index of Direct Rendering Manager,
// Blanks screen if true, unblanks if false.
- virtual void blank_screen(bool blank);
+ virtual void blank_screen(bool blank, int drm);
+
+ // Rotate screen.
+ virtual void rotate_screen(int drm);
static std::unique_ptr<HealthdDraw> Create(animation *anim);
diff --git a/healthd/healthd_mode_charger.cpp b/healthd/healthd_mode_charger.cpp
index 0f9779c..9fe85d4 100644
--- a/healthd/healthd_mode_charger.cpp
+++ b/healthd/healthd_mode_charger.cpp
@@ -327,7 +327,7 @@
#if !defined(__ANDROID_VNDK__)
if (android::sysprop::ChargerProperties::disable_init_blank().value_or(false)) {
- healthd_draw_->blank_screen(true);
+ healthd_draw_->blank_screen(true, static_cast<int>(drm_));
screen_blanked_ = true;
}
#endif
@@ -337,7 +337,7 @@
if (batt_anim_.num_cycles > 0 && batt_anim_.cur_cycle == batt_anim_.num_cycles) {
reset_animation(&batt_anim_);
next_screen_transition_ = -1;
- healthd_draw_->blank_screen(true);
+ healthd_draw_->blank_screen(true, static_cast<int>(drm_));
screen_blanked_ = true;
LOGV("[%" PRId64 "] animation done\n", now);
if (configuration_->ChargerIsOnline()) {
@@ -348,8 +348,17 @@
disp_time = batt_anim_.frames[batt_anim_.cur_frame].disp_time;
+ /* turn off all screen */
+ if (screen_switch_ == SCREEN_SWITCH_ENABLE) {
+ healthd_draw_->blank_screen(true, 0 /* drm */);
+ healthd_draw_->blank_screen(true, 1 /* drm */);
+ healthd_draw_->rotate_screen(static_cast<int>(drm_));
+ screen_blanked_ = true;
+ screen_switch_ = SCREEN_SWITCH_DISABLE;
+ }
+
if (screen_blanked_) {
- healthd_draw_->blank_screen(false);
+ healthd_draw_->blank_screen(false, static_cast<int>(drm_));
screen_blanked_ = false;
}
@@ -452,7 +461,26 @@
return 0;
}
+int Charger::SetSwCallback(int code, int value) {
+ if (code > SW_MAX) return -1;
+ if (code == SW_LID) {
+ if ((screen_switch_ == SCREEN_SWITCH_DEFAULT) || ((value != 0) && (drm_ == DRM_INNER)) ||
+ ((value == 0) && (drm_ == DRM_OUTER))) {
+ screen_switch_ = SCREEN_SWITCH_ENABLE;
+ drm_ = (value != 0) ? DRM_OUTER : DRM_INNER;
+ keys_[code].pending = true;
+ }
+ }
+
+ return 0;
+}
+
void Charger::UpdateInputState(input_event* ev) {
+ if (ev->type == EV_SW && ev->code == SW_LID) {
+ SetSwCallback(ev->code, ev->value);
+ return;
+ }
+
if (ev->type != EV_KEY) return;
SetKeyCallback(ev->code, ev->value);
}
@@ -511,10 +539,26 @@
key->pending = false;
}
+void Charger::ProcessHallSensor(int code) {
+ key_state* key = &keys_[code];
+
+ if (code == SW_LID) {
+ if (key->pending) {
+ reset_animation(&batt_anim_);
+ kick_animation(&batt_anim_);
+ RequestDisableSuspend();
+ }
+ }
+
+ key->pending = false;
+}
+
void Charger::HandleInputState(int64_t now) {
ProcessKey(KEY_POWER, now);
if (next_key_check_ != -1 && now > next_key_check_) next_key_check_ = -1;
+
+ ProcessHallSensor(SW_LID);
}
void Charger::HandlePowerSupplyState(int64_t now) {
@@ -743,9 +787,14 @@
batt_anim_.frames[i].surface = scale_frames[i];
}
}
+ drm_ = DRM_INNER;
+ screen_switch_ = SCREEN_SWITCH_DEFAULT;
ev_sync_key_state(std::bind(&Charger::SetKeyCallback, this, std::placeholders::_1,
std::placeholders::_2));
+ (void)ev_sync_sw_state(
+ std::bind(&Charger::SetSwCallback, this, std::placeholders::_1, std::placeholders::_2));
+
next_screen_transition_ = -1;
next_key_check_ = -1;
next_pwr_check_ = -1;
diff --git a/healthd/include/healthd/BatteryMonitor.h b/healthd/include/healthd/BatteryMonitor.h
index 3cda727..89c2e25 100644
--- a/healthd/include/healthd/BatteryMonitor.h
+++ b/healthd/include/healthd/BatteryMonitor.h
@@ -48,7 +48,8 @@
ANDROID_POWER_SUPPLY_TYPE_AC,
ANDROID_POWER_SUPPLY_TYPE_USB,
ANDROID_POWER_SUPPLY_TYPE_WIRELESS,
- ANDROID_POWER_SUPPLY_TYPE_BATTERY
+ ANDROID_POWER_SUPPLY_TYPE_BATTERY,
+ ANDROID_POWER_SUPPLY_TYPE_DOCK
};
BatteryMonitor();
@@ -75,6 +76,8 @@
bool mBatteryDevicePresent;
int mBatteryFixedCapacity;
int mBatteryFixedTemperature;
+ // TODO(b/214126090): to migrate to AIDL HealthInfo
+ bool mChargerDockOnline;
std::unique_ptr<android::hardware::health::V2_1::HealthInfo> mHealthInfo;
int readFromFile(const String8& path, std::string* buf);
diff --git a/healthd/include_charger/charger/healthd_mode_charger.h b/healthd/include_charger/charger/healthd_mode_charger.h
index 216e5ad..28e1fb5 100644
--- a/healthd/include_charger/charger/healthd_mode_charger.h
+++ b/healthd/include_charger/charger/healthd_mode_charger.h
@@ -44,6 +44,17 @@
aidl::android::hardware::health::BatteryStatus battery_status;
};
+enum DirectRenderManager {
+ DRM_INNER,
+ DRM_OUTER,
+};
+
+enum SrceenSwitch {
+ SCREEN_SWITCH_DEFAULT,
+ SCREEN_SWITCH_DISABLE,
+ SCREEN_SWITCH_ENABLE,
+};
+
// Configuration interface for charger. This includes:
// - HalHealthLoop APIs that interests charger.
// - configuration values that used to be provided by sysprops
@@ -85,9 +96,11 @@
void InitDefaultAnimationFrames();
void UpdateScreenState(int64_t now);
int SetKeyCallback(int code, int value);
+ int SetSwCallback(int code, int value);
void UpdateInputState(input_event* ev);
void SetNextKeyCheck(key_state* key, int64_t timeout);
void ProcessKey(int code, int64_t now);
+ void ProcessHallSensor(int code);
void HandleInputState(int64_t now);
void HandlePowerSupplyState(int64_t now);
int InputCallback(int fd, unsigned int epevents);
@@ -102,6 +115,9 @@
int64_t next_pwr_check_ = 0;
int64_t wait_batt_level_timestamp_ = 0;
+ DirectRenderManager drm_;
+ SrceenSwitch screen_switch_;
+
key_state keys_[KEY_MAX + 1] = {};
animation batt_anim_;
diff --git a/init/init.cpp b/init/init.cpp
index e3596cb..1df4c44 100644
--- a/init/init.cpp
+++ b/init/init.cpp
@@ -33,6 +33,7 @@
#define _REALLY_INCLUDE_SYS__SYSTEM_PROPERTIES_H_
#include <sys/_system_properties.h>
+#include <filesystem>
#include <functional>
#include <map>
#include <memory>
@@ -46,6 +47,7 @@
#include <android-base/logging.h>
#include <android-base/parseint.h>
#include <android-base/properties.h>
+#include <android-base/scopeguard.h>
#include <android-base/stringprintf.h>
#include <android-base/strings.h>
#include <backtrace/Backtrace.h>
@@ -773,6 +775,82 @@
return {};
}
+static bool SystemReadSmokeTest() {
+ std::string dev = "/dev/block/mapper/system"s + fs_mgr_get_slot_suffix();
+ android::base::unique_fd fd(open(dev.c_str(), O_RDONLY));
+ if (fd < 0) {
+ PLOG(ERROR) << "open " << dev << " failed, will not diangose snapuserd hangs";
+ return false;
+ }
+
+ for (size_t i = 1; i <= 100; i++) {
+ // Skip around the partition a bit.
+ size_t offset = i * 4096 * 512;
+
+ char b;
+ ssize_t n = TEMP_FAILURE_RETRY(pread(fd.get(), &b, 1, offset));
+ if (n < 0) {
+ PLOG(ERROR) << "snapuserd smoke test read failed";
+ return false;
+ }
+ }
+ return true;
+}
+
+static void DiagnoseSnapuserdHang(pid_t pid) {
+ bool succeeded = false;
+
+ std::mutex m;
+ std::condition_variable cv;
+
+ // Enforce an ordering between this and the thread startup, by taking the
+ // lock before we lanuch the thread.
+ std::unique_lock<std::mutex> cv_lock(m);
+
+ std::thread t([&]() -> void {
+ std::lock_guard<std::mutex> lock(m);
+ succeeded = SystemReadSmokeTest();
+ cv.notify_all();
+ });
+
+ auto join = android::base::make_scope_guard([&]() -> void {
+ // If the smoke test is hung, then this will too. We expect the device to
+ // automatically reboot once the watchdog kicks in.
+ t.join();
+ });
+
+ auto now = std::chrono::system_clock::now();
+ auto deadline = now + 10s;
+ auto status = cv.wait_until(cv_lock, deadline);
+ if (status == std::cv_status::timeout) {
+ LOG(ERROR) << "snapuserd smoke test timed out";
+ } else if (!succeeded) {
+ LOG(ERROR) << "snapuserd smoke test failed";
+ }
+
+ if (succeeded) {
+ LOG(INFO) << "snapuserd smoke test succeeded";
+ return;
+ }
+
+ while (true) {
+ LOG(ERROR) << "snapuserd problem detected, printing open fds";
+
+ std::error_code ec;
+ std::string proc_dir = "/proc/" + std::to_string(pid) + "/fd";
+ for (const auto& entry : std::filesystem::directory_iterator(proc_dir)) {
+ std::string target;
+ if (android::base::Readlink(entry.path(), &target)) {
+ LOG(ERROR) << "snapuserd opened: " << target;
+ } else {
+ LOG(ERROR) << "snapuserd opened: " << entry.path();
+ }
+ }
+
+ std::this_thread::sleep_for(10s);
+ }
+}
+
int SecondStageMain(int argc, char** argv) {
if (REBOOT_BOOTLOADER_ON_PANIC) {
InstallRebootSignalHandlers();
@@ -786,6 +864,11 @@
InitKernelLogging(argv);
LOG(INFO) << "init second stage started!";
+ if (auto pid = GetSnapuserdFirstStagePid()) {
+ std::thread t(DiagnoseSnapuserdHang, *pid);
+ t.detach();
+ }
+
// Update $PATH in the case the second stage init is newer than first stage init, where it is
// first set.
if (setenv("PATH", _PATH_DEFPATH, 1) != 0) {
diff --git a/init/perfboot.py b/init/perfboot.py
index 4b23ad2..968df38 100755
--- a/init/perfboot.py
+++ b/init/perfboot.py
@@ -1,4 +1,4 @@
-#!/usr/bin/env python
+#!/usr/bin/env python3
# Copyright (C) 2015 The Android Open Source Project
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -39,7 +39,7 @@
import argparse
import atexit
-import cStringIO
+import io
import glob
import inspect
import logging
@@ -102,7 +102,7 @@
self._wait_cpu_cool_down(self._product, self._temp_paths)
else:
if self._waited:
- print 'Waiting for %d seconds' % self._interval
+ print('Waiting for %d seconds' % self._interval)
time.sleep(self._interval)
self._waited = True
@@ -119,9 +119,9 @@
threshold = IntervalAdjuster._CPU_COOL_DOWN_THRESHOLDS.get(
self._product)
if threshold is None:
- print 'No CPU temperature threshold is set for ' + self._product
- print ('Just wait %d seconds' %
- IntervalAdjuster._CPU_COOL_DOWN_WAIT_TIME_DEFAULT)
+ print('No CPU temperature threshold is set for ' + self._product)
+ print(('Just wait %d seconds' %
+ IntervalAdjuster._CPU_COOL_DOWN_WAIT_TIME_DEFAULT))
time.sleep(IntervalAdjuster._CPU_COOL_DOWN_WAIT_TIME_DEFAULT)
return
while True:
@@ -129,8 +129,8 @@
if temp < threshold:
logging.info('Current CPU temperature %s' % temp)
return
- print 'Waiting until CPU temperature (%d) falls below %d' % (
- temp, threshold)
+ print('Waiting until CPU temperature (%d) falls below %d' % (
+ temp, threshold))
time.sleep(IntervalAdjuster._CPU_COOL_DOWN_WAIT_INTERVAL)
@@ -260,7 +260,7 @@
def get_values(record, tag):
"""Gets values that matches |tag| from |record|."""
- keys = [key for key in record.keys() if key[0] == tag]
+ keys = [key for key in list(record.keys()) if key[0] == tag]
return [record[k] for k in sorted(keys)]
@@ -304,7 +304,7 @@
with open(filename, 'w') as f:
f.write('\t'.join(labels) + '\n')
for record in record_list:
- line = cStringIO.StringIO()
+ line = io.StringIO()
invalid_line = False
for i, tag in enumerate(tags):
if i != 0:
@@ -319,7 +319,7 @@
logging.error('Invalid record found: ' + line.getvalue())
line.write('\n')
f.write(line.getvalue())
- print 'Wrote: ' + filename
+ print(('Wrote: ' + filename))
def median(data):
@@ -349,9 +349,9 @@
# Filter out invalid data.
end_times = [get_last_value(record, end_tag) for record in record_list
if get_last_value(record, end_tag) != 0]
- print 'mean:', int(round(mean(end_times))), 'ms'
- print 'median:', int(round(median(end_times))), 'ms'
- print 'standard deviation:', int(round(stddev(end_times))), 'ms'
+ print(('mean:', int(round(mean(end_times))), 'ms'))
+ print(('median:', int(round(median(end_times))), 'ms'))
+ print(('standard deviation:', int(round(stddev(end_times))), 'ms'))
def do_iteration(device, interval_adjuster, event_tags_re, end_tag):
@@ -359,7 +359,7 @@
device.wait()
interval_adjuster.wait()
device.reboot()
- print 'Rebooted the device'
+ print('Rebooted the device, waiting for tag', end_tag)
record = {}
booted = False
while not booted:
@@ -372,7 +372,7 @@
stdout=subprocess.PIPE)
for line in readlines_unbuffered(p):
if t.is_timedout():
- print '*** Timed out ***'
+ print('*** Timed out ***')
return record
m = event_tags_re.search(line)
if not m:
@@ -381,8 +381,8 @@
event_time = int(m.group('time'))
pid = m.group('pid')
record[(tag, pid)] = event_time
- print 'Event log recorded: %s (%s) - %d ms' % (
- tag, pid, event_time)
+ print(('Event log recorded: %s (%s) - %d ms' % (
+ tag, pid, event_time)))
if tag == end_tag:
booted = True
t.cancel()
@@ -420,7 +420,7 @@
def install_apks(device, apk_dir):
for apk in glob.glob(os.path.join(apk_dir, '*.apk')):
- print 'Installing: ' + apk
+ print('Installing: ' + apk)
device.install(apk, replace=True)
@@ -452,7 +452,7 @@
event_tags_re = make_event_tags_re(event_tags)
for i in range(args.iterations):
- print 'Run #%d ' % i
+ print('Run #%d ' % i)
record = do_iteration(
device, interval_adjuster, event_tags_re, end_tag)
record_list.append(record)
diff --git a/init/snapuserd_transition.cpp b/init/snapuserd_transition.cpp
index e11510e..5deaf31 100644
--- a/init/snapuserd_transition.cpp
+++ b/init/snapuserd_transition.cpp
@@ -32,6 +32,7 @@
#include <android-base/strings.h>
#include <android-base/unique_fd.h>
#include <cutils/sockets.h>
+#include <fs_avb/fs_avb.h>
#include <libsnapshot/snapshot.h>
#include <private/android_filesystem_config.h>
#include <procinfo/process_map.h>
@@ -247,6 +248,56 @@
}
}
+/*
+ * Before starting init second stage, we will wait
+ * for snapuserd daemon to be up and running; bionic libc
+ * may read /system/etc/selinux/plat_property_contexts file
+ * before invoking main() function. This will happen if
+ * init initializes property during second stage. Any access
+ * to /system without snapuserd daemon will lead to a deadlock.
+ *
+ * Thus, we do a simple probe by reading system partition. This
+ * read will eventually be serviced by daemon confirming that
+ * daemon is up and running. Furthermore, we are still in the kernel
+ * domain and sepolicy has not been enforced yet. Thus, access
+ * to these device mapper block devices are ok even though
+ * we may see audit logs.
+ */
+bool SnapuserdSelinuxHelper::TestSnapuserdIsReady() {
+ 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) {
+ PLOG(ERROR) << "open " << dev << " failed";
+ return false;
+ }
+
+ void* addr;
+ ssize_t page_size = getpagesize();
+ if (posix_memalign(&addr, page_size, page_size) < 0) {
+ PLOG(ERROR) << "posix_memalign with page size " << page_size;
+ return false;
+ }
+
+ std::unique_ptr<void, decltype(&::free)> buffer(addr, ::free);
+
+ int iter = 0;
+ while (iter < 10) {
+ ssize_t n = TEMP_FAILURE_RETRY(pread(fd.get(), buffer.get(), page_size, 0));
+ if (n < 0) {
+ // Wait for sometime before retry
+ std::this_thread::sleep_for(100ms);
+ } else if (n == page_size) {
+ return true;
+ } else {
+ LOG(ERROR) << "pread returned: " << n << " from: " << dev << " expected: " << page_size;
+ }
+
+ iter += 1;
+ }
+
+ return false;
+}
+
void SnapuserdSelinuxHelper::RelaunchFirstStageSnapuserd() {
auto fd = GetRamdiskSnapuserdFd();
if (!fd) {
@@ -268,6 +319,13 @@
setenv(kSnapuserdFirstStagePidVar, std::to_string(pid).c_str(), 1);
LOG(INFO) << "Relaunched snapuserd with pid: " << pid;
+
+ if (!TestSnapuserdIsReady()) {
+ PLOG(FATAL) << "snapuserd daemon failed to launch";
+ } else {
+ LOG(INFO) << "snapuserd daemon is up and running";
+ }
+
return;
}
diff --git a/init/snapuserd_transition.h b/init/snapuserd_transition.h
index be22afd..557d105 100644
--- a/init/snapuserd_transition.h
+++ b/init/snapuserd_transition.h
@@ -56,6 +56,7 @@
private:
void RelaunchFirstStageSnapuserd();
void ExecSnapuserd();
+ bool TestSnapuserdIsReady();
std::unique_ptr<SnapshotManager> sm_;
BlockDevInitializer block_dev_init_;
diff --git a/libprocessgroup/include/processgroup/processgroup.h b/libprocessgroup/include/processgroup/processgroup.h
index be34f95..c5badc9 100644
--- a/libprocessgroup/include/processgroup/processgroup.h
+++ b/libprocessgroup/include/processgroup/processgroup.h
@@ -35,6 +35,8 @@
#ifndef __ANDROID_VNDK__
+bool SetProcessProfilesCached(uid_t uid, pid_t pid, const std::vector<std::string>& profiles);
+
static constexpr const char* CGROUPS_RC_PATH = "/dev/cgroup_info/cgroup.rc";
bool UsePerAppMemcg();
diff --git a/libprocessgroup/processgroup.cpp b/libprocessgroup/processgroup.cpp
index 0320b02..cb2fe0a 100644
--- a/libprocessgroup/processgroup.cpp
+++ b/libprocessgroup/processgroup.cpp
@@ -126,11 +126,16 @@
}
void DropTaskProfilesResourceCaching() {
- TaskProfiles::GetInstance().DropResourceCaching();
+ TaskProfiles::GetInstance().DropResourceCaching(ProfileAction::RCT_TASK);
+ TaskProfiles::GetInstance().DropResourceCaching(ProfileAction::RCT_PROCESS);
}
bool SetProcessProfiles(uid_t uid, pid_t pid, const std::vector<std::string>& profiles) {
- return TaskProfiles::GetInstance().SetProcessProfiles(uid, pid, profiles);
+ return TaskProfiles::GetInstance().SetProcessProfiles(uid, pid, profiles, false);
+}
+
+bool SetProcessProfilesCached(uid_t uid, pid_t pid, const std::vector<std::string>& profiles) {
+ return TaskProfiles::GetInstance().SetProcessProfiles(uid, pid, profiles, true);
}
bool SetTaskProfiles(int tid, const std::vector<std::string>& profiles, bool use_fd_cache) {
diff --git a/libprocessgroup/task_profiles.cpp b/libprocessgroup/task_profiles.cpp
index 3834f91..74ba7f6 100644
--- a/libprocessgroup/task_profiles.cpp
+++ b/libprocessgroup/task_profiles.cpp
@@ -51,6 +51,67 @@
static constexpr const char* TEMPLATE_TASK_PROFILE_API_FILE =
"/etc/task_profiles/task_profiles_%u.json";
+class FdCacheHelper {
+ public:
+ enum FdState {
+ FDS_INACCESSIBLE = -1,
+ FDS_APP_DEPENDENT = -2,
+ FDS_NOT_CACHED = -3,
+ };
+
+ static void Cache(const std::string& path, android::base::unique_fd& fd);
+ static void Drop(android::base::unique_fd& fd);
+ static void Init(const std::string& path, android::base::unique_fd& fd);
+ static bool IsCached(const android::base::unique_fd& fd) { return fd > FDS_INACCESSIBLE; }
+
+ private:
+ static bool IsAppDependentPath(const std::string& path);
+};
+
+void FdCacheHelper::Init(const std::string& path, android::base::unique_fd& fd) {
+ // file descriptors for app-dependent paths can't be cached
+ if (IsAppDependentPath(path)) {
+ // file descriptor is not cached
+ fd.reset(FDS_APP_DEPENDENT);
+ return;
+ }
+ // file descriptor can be cached later on request
+ fd.reset(FDS_NOT_CACHED);
+}
+
+void FdCacheHelper::Cache(const std::string& path, android::base::unique_fd& fd) {
+ if (fd != FDS_NOT_CACHED) {
+ return;
+ }
+
+ if (access(path.c_str(), W_OK) != 0) {
+ // file is not accessible
+ fd.reset(FDS_INACCESSIBLE);
+ return;
+ }
+
+ unique_fd tmp_fd(TEMP_FAILURE_RETRY(open(path.c_str(), O_WRONLY | O_CLOEXEC)));
+ if (tmp_fd < 0) {
+ PLOG(ERROR) << "Failed to cache fd '" << path << "'";
+ fd.reset(FDS_INACCESSIBLE);
+ return;
+ }
+
+ fd = std::move(tmp_fd);
+}
+
+void FdCacheHelper::Drop(android::base::unique_fd& fd) {
+ if (fd == FDS_NOT_CACHED) {
+ return;
+ }
+
+ fd.reset(FDS_NOT_CACHED);
+}
+
+bool FdCacheHelper::IsAppDependentPath(const std::string& path) {
+ return path.find("<uid>", 0) != std::string::npos || path.find("<pid>", 0) != std::string::npos;
+}
+
void ProfileAttribute::Reset(const CgroupController& controller, const std::string& file_name) {
controller_ = controller;
file_name_ = file_name;
@@ -144,57 +205,11 @@
return true;
}
-void CachedFdProfileAction::EnableResourceCaching() {
- std::lock_guard<std::mutex> lock(fd_mutex_);
- if (fd_ != FDS_NOT_CACHED) {
- return;
- }
-
- std::string tasks_path = GetPath();
-
- if (access(tasks_path.c_str(), W_OK) != 0) {
- // file is not accessible
- fd_.reset(FDS_INACCESSIBLE);
- return;
- }
-
- unique_fd fd(TEMP_FAILURE_RETRY(open(tasks_path.c_str(), O_WRONLY | O_CLOEXEC)));
- if (fd < 0) {
- PLOG(ERROR) << "Failed to cache fd '" << tasks_path << "'";
- fd_.reset(FDS_INACCESSIBLE);
- return;
- }
-
- fd_ = std::move(fd);
-}
-
-void CachedFdProfileAction::DropResourceCaching() {
- std::lock_guard<std::mutex> lock(fd_mutex_);
- if (fd_ == FDS_NOT_CACHED) {
- return;
- }
-
- fd_.reset(FDS_NOT_CACHED);
-}
-
-bool CachedFdProfileAction::IsAppDependentPath(const std::string& path) {
- return path.find("<uid>", 0) != std::string::npos || path.find("<pid>", 0) != std::string::npos;
-}
-
-void CachedFdProfileAction::InitFd(const std::string& path) {
- // file descriptors for app-dependent paths can't be cached
- if (IsAppDependentPath(path)) {
- // file descriptor is not cached
- fd_.reset(FDS_APP_DEPENDENT);
- return;
- }
- // file descriptor can be cached later on request
- fd_.reset(FDS_NOT_CACHED);
-}
-
SetCgroupAction::SetCgroupAction(const CgroupController& c, const std::string& p)
: controller_(c), path_(p) {
- InitFd(controller_.GetTasksFilePath(path_));
+ FdCacheHelper::Init(controller_.GetTasksFilePath(path_), fd_[ProfileAction::RCT_TASK]);
+ // uid and pid don't matter because IsAppDependentPath ensures the path doesn't use them
+ FdCacheHelper::Init(controller_.GetProcsFilePath(path_, 0, 0), fd_[ProfileAction::RCT_PROCESS]);
}
bool SetCgroupAction::AddTidToCgroup(int tid, int fd, const char* controller_name) {
@@ -232,7 +247,40 @@
return false;
}
+ProfileAction::CacheUseResult SetCgroupAction::UseCachedFd(ResourceCacheType cache_type,
+ int id) const {
+ std::lock_guard<std::mutex> lock(fd_mutex_);
+ if (FdCacheHelper::IsCached(fd_[cache_type])) {
+ // fd is cached, reuse it
+ if (!AddTidToCgroup(id, fd_[cache_type], controller()->name())) {
+ LOG(ERROR) << "Failed to add task into cgroup";
+ return ProfileAction::FAIL;
+ }
+ return ProfileAction::SUCCESS;
+ }
+
+ if (fd_[cache_type] == FdCacheHelper::FDS_INACCESSIBLE) {
+ // no permissions to access the file, ignore
+ return ProfileAction::SUCCESS;
+ }
+
+ if (cache_type == ResourceCacheType::RCT_TASK &&
+ fd_[cache_type] == FdCacheHelper::FDS_APP_DEPENDENT) {
+ // application-dependent path can't be used with tid
+ PLOG(ERROR) << "Application profile can't be applied to a thread";
+ return ProfileAction::FAIL;
+ }
+
+ return ProfileAction::UNUSED;
+}
+
bool SetCgroupAction::ExecuteForProcess(uid_t uid, pid_t pid) const {
+ CacheUseResult result = UseCachedFd(ProfileAction::RCT_PROCESS, pid);
+ if (result != ProfileAction::UNUSED) {
+ return result == ProfileAction::SUCCESS;
+ }
+
+ // fd was not cached or cached fd can't be used
std::string procs_path = controller()->GetProcsFilePath(path_, uid, pid);
unique_fd tmp_fd(TEMP_FAILURE_RETRY(open(procs_path.c_str(), O_WRONLY | O_CLOEXEC)));
if (tmp_fd < 0) {
@@ -248,28 +296,12 @@
}
bool SetCgroupAction::ExecuteForTask(int tid) const {
- std::lock_guard<std::mutex> lock(fd_mutex_);
- if (IsFdValid()) {
- // fd is cached, reuse it
- if (!AddTidToCgroup(tid, fd_, controller()->name())) {
- LOG(ERROR) << "Failed to add task into cgroup";
- return false;
- }
- return true;
+ CacheUseResult result = UseCachedFd(ProfileAction::RCT_TASK, tid);
+ if (result != ProfileAction::UNUSED) {
+ return result == ProfileAction::SUCCESS;
}
- if (fd_ == FDS_INACCESSIBLE) {
- // no permissions to access the file, ignore
- return true;
- }
-
- if (fd_ == FDS_APP_DEPENDENT) {
- // application-dependent path can't be used with tid
- PLOG(ERROR) << "Application profile can't be applied to a thread";
- return false;
- }
-
- // fd was not cached because cached fd can't be used
+ // fd was not cached or cached fd can't be used
std::string tasks_path = controller()->GetTasksFilePath(path_);
unique_fd tmp_fd(TEMP_FAILURE_RETRY(open(tasks_path.c_str(), O_WRONLY | O_CLOEXEC)));
if (tmp_fd < 0) {
@@ -284,10 +316,36 @@
return true;
}
+void SetCgroupAction::EnableResourceCaching(ResourceCacheType cache_type) {
+ std::lock_guard<std::mutex> lock(fd_mutex_);
+ // Return early to prevent unnecessary calls to controller_.Get{Tasks|Procs}FilePath() which
+ // include regex evaluations
+ if (fd_[cache_type] != FdCacheHelper::FDS_NOT_CACHED) {
+ return;
+ }
+ switch (cache_type) {
+ case (ProfileAction::RCT_TASK):
+ FdCacheHelper::Cache(controller_.GetTasksFilePath(path_), fd_[cache_type]);
+ break;
+ case (ProfileAction::RCT_PROCESS):
+ // uid and pid don't matter because IsAppDependentPath ensures the path doesn't use them
+ FdCacheHelper::Cache(controller_.GetProcsFilePath(path_, 0, 0), fd_[cache_type]);
+ break;
+ default:
+ LOG(ERROR) << "Invalid cache type is specified!";
+ break;
+ }
+}
+
+void SetCgroupAction::DropResourceCaching(ResourceCacheType cache_type) {
+ std::lock_guard<std::mutex> lock(fd_mutex_);
+ FdCacheHelper::Drop(fd_[cache_type]);
+}
+
WriteFileAction::WriteFileAction(const std::string& path, const std::string& value,
bool logfailures)
: path_(path), value_(value), logfailures_(logfailures) {
- InitFd(path_);
+ FdCacheHelper::Init(path_, fd_);
}
bool WriteFileAction::WriteValueToFile(const std::string& value, const std::string& path,
@@ -309,13 +367,43 @@
return true;
}
-bool WriteFileAction::ExecuteForProcess(uid_t uid, pid_t pid) const {
+ProfileAction::CacheUseResult WriteFileAction::UseCachedFd(ResourceCacheType cache_type,
+ const std::string& value) const {
std::lock_guard<std::mutex> lock(fd_mutex_);
+ if (FdCacheHelper::IsCached(fd_)) {
+ // fd is cached, reuse it
+ if (!WriteStringToFd(value, fd_)) {
+ if (logfailures_) PLOG(ERROR) << "Failed to write '" << value << "' to " << path_;
+ return ProfileAction::FAIL;
+ }
+ return ProfileAction::SUCCESS;
+ }
+
+ if (fd_ == FdCacheHelper::FDS_INACCESSIBLE) {
+ // no permissions to access the file, ignore
+ return ProfileAction::SUCCESS;
+ }
+
+ if (cache_type == ResourceCacheType::RCT_TASK && fd_ == FdCacheHelper::FDS_APP_DEPENDENT) {
+ // application-dependent path can't be used with tid
+ PLOG(ERROR) << "Application profile can't be applied to a thread";
+ return ProfileAction::FAIL;
+ }
+ return ProfileAction::UNUSED;
+}
+
+bool WriteFileAction::ExecuteForProcess(uid_t uid, pid_t pid) const {
std::string value(value_);
- std::string path(path_);
value = StringReplace(value, "<uid>", std::to_string(uid), true);
value = StringReplace(value, "<pid>", std::to_string(pid), true);
+
+ CacheUseResult result = UseCachedFd(ProfileAction::RCT_PROCESS, value);
+ if (result != ProfileAction::UNUSED) {
+ return result == ProfileAction::SUCCESS;
+ }
+
+ std::string path(path_);
path = StringReplace(path, "<uid>", std::to_string(uid), true);
path = StringReplace(path, "<pid>", std::to_string(pid), true);
@@ -323,41 +411,33 @@
}
bool WriteFileAction::ExecuteForTask(int tid) const {
- std::lock_guard<std::mutex> lock(fd_mutex_);
std::string value(value_);
int uid = getuid();
value = StringReplace(value, "<uid>", std::to_string(uid), true);
value = StringReplace(value, "<pid>", std::to_string(tid), true);
- if (IsFdValid()) {
- // fd is cached, reuse it
- if (!WriteStringToFd(value, fd_)) {
- if (logfailures_) PLOG(ERROR) << "Failed to write '" << value << "' to " << path_;
- return false;
- }
- return true;
- }
-
- if (fd_ == FDS_INACCESSIBLE) {
- // no permissions to access the file, ignore
- return true;
- }
-
- if (fd_ == FDS_APP_DEPENDENT) {
- // application-dependent path can't be used with tid
- PLOG(ERROR) << "Application profile can't be applied to a thread";
- return false;
+ CacheUseResult result = UseCachedFd(ProfileAction::RCT_TASK, value);
+ if (result != ProfileAction::UNUSED) {
+ return result == ProfileAction::SUCCESS;
}
return WriteValueToFile(value, path_, logfailures_);
}
+void WriteFileAction::EnableResourceCaching(ResourceCacheType) {
+ std::lock_guard<std::mutex> lock(fd_mutex_);
+ FdCacheHelper::Cache(path_, fd_);
+}
+
+void WriteFileAction::DropResourceCaching(ResourceCacheType) {
+ std::lock_guard<std::mutex> lock(fd_mutex_);
+ FdCacheHelper::Drop(fd_);
+}
+
bool ApplyProfileAction::ExecuteForProcess(uid_t uid, pid_t pid) const {
for (const auto& profile : profiles_) {
- if (!profile->ExecuteForProcess(uid, pid)) {
- PLOG(WARNING) << "ExecuteForProcess failed for aggregate profile";
- }
+ profile->ExecuteForProcess(uid, pid);
}
return true;
}
@@ -369,15 +449,15 @@
return true;
}
-void ApplyProfileAction::EnableResourceCaching() {
+void ApplyProfileAction::EnableResourceCaching(ResourceCacheType cache_type) {
for (const auto& profile : profiles_) {
- profile->EnableResourceCaching();
+ profile->EnableResourceCaching(cache_type);
}
}
-void ApplyProfileAction::DropResourceCaching() {
+void ApplyProfileAction::DropResourceCaching(ResourceCacheType cache_type) {
for (const auto& profile : profiles_) {
- profile->DropResourceCaching();
+ profile->DropResourceCaching(cache_type);
}
}
@@ -407,33 +487,33 @@
return true;
}
-void TaskProfile::EnableResourceCaching() {
+void TaskProfile::EnableResourceCaching(ProfileAction::ResourceCacheType cache_type) {
if (res_cached_) {
return;
}
for (auto& element : elements_) {
- element->EnableResourceCaching();
+ element->EnableResourceCaching(cache_type);
}
res_cached_ = true;
}
-void TaskProfile::DropResourceCaching() {
+void TaskProfile::DropResourceCaching(ProfileAction::ResourceCacheType cache_type) {
if (!res_cached_) {
return;
}
for (auto& element : elements_) {
- element->DropResourceCaching();
+ element->DropResourceCaching(cache_type);
}
res_cached_ = false;
}
-void TaskProfiles::DropResourceCaching() const {
+void TaskProfiles::DropResourceCaching(ProfileAction::ResourceCacheType cache_type) const {
for (auto& iter : profiles_) {
- iter.second->DropResourceCaching();
+ iter.second->DropResourceCaching(cache_type);
}
}
@@ -457,8 +537,7 @@
android::base::StringPrintf(TEMPLATE_TASK_PROFILE_API_FILE, api_level);
if (!access(api_profiles_path.c_str(), F_OK) || errno != ENOENT) {
if (!Load(CgroupMap::GetInstance(), api_profiles_path)) {
- LOG(ERROR) << "Loading " << api_profiles_path << " for [" << getpid()
- << "] failed";
+ LOG(ERROR) << "Loading " << api_profiles_path << " for [" << getpid() << "] failed";
}
}
}
@@ -651,10 +730,13 @@
}
bool TaskProfiles::SetProcessProfiles(uid_t uid, pid_t pid,
- const std::vector<std::string>& profiles) {
+ const std::vector<std::string>& profiles, bool use_fd_cache) {
for (const auto& name : profiles) {
TaskProfile* profile = GetProfile(name);
if (profile != nullptr) {
+ if (use_fd_cache) {
+ profile->EnableResourceCaching(ProfileAction::RCT_PROCESS);
+ }
if (!profile->ExecuteForProcess(uid, pid)) {
PLOG(WARNING) << "Failed to apply " << name << " process profile";
}
@@ -671,7 +753,7 @@
TaskProfile* profile = GetProfile(name);
if (profile != nullptr) {
if (use_fd_cache) {
- profile->EnableResourceCaching();
+ profile->EnableResourceCaching(ProfileAction::RCT_TASK);
}
if (!profile->ExecuteForTask(tid)) {
PLOG(WARNING) << "Failed to apply " << name << " task profile";
diff --git a/libprocessgroup/task_profiles.h b/libprocessgroup/task_profiles.h
index 278892d..1aaa196 100644
--- a/libprocessgroup/task_profiles.h
+++ b/libprocessgroup/task_profiles.h
@@ -45,14 +45,19 @@
// Abstract profile element
class ProfileAction {
public:
+ enum ResourceCacheType { RCT_TASK = 0, RCT_PROCESS, RCT_COUNT };
+
virtual ~ProfileAction() {}
// Default implementations will fail
virtual bool ExecuteForProcess(uid_t, pid_t) const { return false; };
virtual bool ExecuteForTask(int) const { return false; };
- virtual void EnableResourceCaching() {}
- virtual void DropResourceCaching() {}
+ virtual void EnableResourceCaching(ResourceCacheType) {}
+ virtual void DropResourceCaching(ResourceCacheType) {}
+
+ protected:
+ enum CacheUseResult { SUCCESS, FAIL, UNUSED };
};
// Profile actions
@@ -108,67 +113,47 @@
std::string value_;
};
-// Abstract profile element for cached fd
-class CachedFdProfileAction : public ProfileAction {
- public:
- virtual void EnableResourceCaching();
- virtual void DropResourceCaching();
-
- protected:
- enum FdState {
- FDS_INACCESSIBLE = -1,
- FDS_APP_DEPENDENT = -2,
- FDS_NOT_CACHED = -3,
- };
-
- android::base::unique_fd fd_;
- mutable std::mutex fd_mutex_;
-
- static bool IsAppDependentPath(const std::string& path);
-
- void InitFd(const std::string& path);
- bool IsFdValid() const { return fd_ > FDS_INACCESSIBLE; }
-
- virtual const std::string GetPath() const = 0;
-};
-
// Set cgroup profile element
-class SetCgroupAction : public CachedFdProfileAction {
+class SetCgroupAction : public ProfileAction {
public:
SetCgroupAction(const CgroupController& c, const std::string& p);
virtual bool ExecuteForProcess(uid_t uid, pid_t pid) const;
virtual bool ExecuteForTask(int tid) const;
+ virtual void EnableResourceCaching(ResourceCacheType cache_type);
+ virtual void DropResourceCaching(ResourceCacheType cache_type);
const CgroupController* controller() const { return &controller_; }
- protected:
- const std::string GetPath() const override { return controller_.GetTasksFilePath(path_); }
-
private:
CgroupController controller_;
std::string path_;
+ android::base::unique_fd fd_[ProfileAction::RCT_COUNT];
+ mutable std::mutex fd_mutex_;
static bool AddTidToCgroup(int tid, int fd, const char* controller_name);
+ CacheUseResult UseCachedFd(ResourceCacheType cache_type, int id) const;
};
// Write to file action
-class WriteFileAction : public CachedFdProfileAction {
+class WriteFileAction : public ProfileAction {
public:
WriteFileAction(const std::string& path, const std::string& value, bool logfailures);
virtual bool ExecuteForProcess(uid_t uid, pid_t pid) const;
virtual bool ExecuteForTask(int tid) const;
-
- protected:
- const std::string GetPath() const override { return path_; }
+ virtual void EnableResourceCaching(ResourceCacheType cache_type);
+ virtual void DropResourceCaching(ResourceCacheType cache_type);
private:
std::string path_, value_;
bool logfailures_;
+ android::base::unique_fd fd_;
+ mutable std::mutex fd_mutex_;
static bool WriteValueToFile(const std::string& value, const std::string& path,
bool logfailures);
+ CacheUseResult UseCachedFd(ResourceCacheType cache_type, const std::string& value) const;
};
class TaskProfile {
@@ -180,8 +165,8 @@
bool ExecuteForProcess(uid_t uid, pid_t pid) const;
bool ExecuteForTask(int tid) const;
- void EnableResourceCaching();
- void DropResourceCaching();
+ void EnableResourceCaching(ProfileAction::ResourceCacheType cache_type);
+ void DropResourceCaching(ProfileAction::ResourceCacheType cache_type);
private:
bool res_cached_;
@@ -196,8 +181,8 @@
virtual bool ExecuteForProcess(uid_t uid, pid_t pid) const;
virtual bool ExecuteForTask(int tid) const;
- virtual void EnableResourceCaching();
- virtual void DropResourceCaching();
+ virtual void EnableResourceCaching(ProfileAction::ResourceCacheType cache_type);
+ virtual void DropResourceCaching(ProfileAction::ResourceCacheType cache_type);
private:
std::vector<std::shared_ptr<TaskProfile>> profiles_;
@@ -210,8 +195,9 @@
TaskProfile* GetProfile(const std::string& name) const;
const ProfileAttribute* GetAttribute(const std::string& name) const;
- void DropResourceCaching() const;
- bool SetProcessProfiles(uid_t uid, pid_t pid, const std::vector<std::string>& profiles);
+ void DropResourceCaching(ProfileAction::ResourceCacheType cache_type) const;
+ bool SetProcessProfiles(uid_t uid, pid_t pid, const std::vector<std::string>& profiles,
+ bool use_fd_cache);
bool SetTaskProfiles(int tid, const std::vector<std::string>& profiles, bool use_fd_cache);
private:
diff --git a/libsparse/img2simg.cpp b/libsparse/img2simg.cpp
index 4c2c6ca..3e24cc0 100644
--- a/libsparse/img2simg.cpp
+++ b/libsparse/img2simg.cpp
@@ -93,7 +93,7 @@
}
sparse_file_verbose(s);
- ret = sparse_file_read(s, in, false, false);
+ ret = sparse_file_read(s, in, SPARSE_READ_MODE_NORMAL, false);
if (ret) {
fprintf(stderr, "Failed to read file\n");
exit(-1);
diff --git a/libsparse/include/sparse/sparse.h b/libsparse/include/sparse/sparse.h
index 9f91269..7c52c3f 100644
--- a/libsparse/include/sparse/sparse.h
+++ b/libsparse/include/sparse/sparse.h
@@ -225,23 +225,42 @@
int (*write)(void *priv, const void *data, size_t len, unsigned int block,
unsigned int nr_blocks),
void *priv);
+
+/**
+ * enum sparse_read_mode - The method to use when reading in files
+ * @SPARSE_READ_MODE_NORMAL: The input is a regular file. Constant chunks of
+ * data (including holes) will be be converted to
+ * fill chunks.
+ * @SPARSE_READ_MODE_SPARSE: The input is an Android sparse file.
+ * @SPARSE_READ_MODE_HOLE: The input is a regular file. Holes will be converted
+ * to "don't care" chunks. Other constant chunks will
+ * be converted to fill chunks.
+ */
+enum sparse_read_mode {
+ SPARSE_READ_MODE_NORMAL = false,
+ SPARSE_READ_MODE_SPARSE = true,
+ SPARSE_READ_MODE_HOLE,
+};
+
/**
* sparse_file_read - read a file into a sparse file cookie
*
* @s - sparse file cookie
* @fd - file descriptor to read from
- * @sparse - read a file in the Android sparse file format
+ * @mode - mode to use when reading the input file
* @crc - verify the crc of a file in the Android sparse file format
*
- * Reads a file into a sparse file cookie. If sparse is true, the file is
- * assumed to be in the Android sparse file format. If sparse is false, the
- * file will be sparsed by looking for block aligned chunks of all zeros or
- * another 32 bit value. If crc is true, the crc of the sparse file will be
- * verified.
+ * Reads a file into a sparse file cookie. If @mode is
+ * %SPARSE_READ_MODE_SPARSE, the file is assumed to be in the Android sparse
+ * file format. If @mode is %SPARSE_READ_MODE_NORMAL, the file will be sparsed
+ * by looking for block aligned chunks of all zeros or another 32 bit value. If
+ * @mode is %SPARSE_READ_MODE_HOLE, the file will be sparsed like
+ * %SPARSE_READ_MODE_NORMAL, but holes in the file will be converted to "don't
+ * care" chunks. If crc is true, the crc of the sparse file will be verified.
*
* Returns 0 on success, negative errno on error.
*/
-int sparse_file_read(struct sparse_file *s, int fd, bool sparse, bool crc);
+int sparse_file_read(struct sparse_file *s, int fd, enum sparse_read_mode mode, bool crc);
/**
* sparse_file_import - import an existing sparse file
diff --git a/libsparse/sparse_read.cpp b/libsparse/sparse_read.cpp
index 0f39172..028b6be 100644
--- a/libsparse/sparse_read.cpp
+++ b/libsparse/sparse_read.cpp
@@ -457,12 +457,10 @@
return 0;
}
-static int sparse_file_read_normal(struct sparse_file* s, int fd) {
+static int do_sparse_file_read_normal(struct sparse_file* s, int fd, uint32_t* buf, int64_t offset,
+ int64_t remain) {
int ret;
- uint32_t* buf = (uint32_t*)malloc(s->block_size);
- unsigned int block = 0;
- int64_t remain = s->len;
- int64_t offset = 0;
+ unsigned int block = offset / s->block_size;
unsigned int to_read;
unsigned int i;
bool sparse_block;
@@ -476,7 +474,6 @@
ret = read_all(fd, buf, to_read);
if (ret < 0) {
error("failed to read sparse file");
- free(buf);
return ret;
}
@@ -504,20 +501,93 @@
block++;
}
- free(buf);
return 0;
}
-int sparse_file_read(struct sparse_file* s, int fd, bool sparse, bool crc) {
- if (crc && !sparse) {
+static int sparse_file_read_normal(struct sparse_file* s, int fd) {
+ int ret;
+ uint32_t* buf = (uint32_t*)malloc(s->block_size);
+
+ if (!buf)
+ return -ENOMEM;
+
+ ret = do_sparse_file_read_normal(s, fd, buf, 0, s->len);
+ free(buf);
+ return ret;
+}
+
+#ifdef __linux__
+static int sparse_file_read_hole(struct sparse_file* s, int fd) {
+ int ret;
+ uint32_t* buf = (uint32_t*)malloc(s->block_size);
+ int64_t end = 0;
+ int64_t start = 0;
+
+ if (!buf) {
+ return -ENOMEM;
+ }
+
+ do {
+ start = lseek(fd, end, SEEK_DATA);
+ if (start < 0) {
+ if (errno == ENXIO)
+ /* The rest of the file is a hole */
+ break;
+
+ error("could not seek to data");
+ free(buf);
+ return -errno;
+ } else if (start > s->len) {
+ break;
+ }
+
+ end = lseek(fd, start, SEEK_HOLE);
+ if (end < 0) {
+ error("could not seek to end");
+ free(buf);
+ return -errno;
+ }
+ end = std::min(end, s->len);
+
+ start = ALIGN_DOWN(start, s->block_size);
+ end = ALIGN(end, s->block_size);
+ if (lseek(fd, start, SEEK_SET) < 0) {
+ free(buf);
+ return -errno;
+ }
+
+ ret = do_sparse_file_read_normal(s, fd, buf, start, end - start);
+ if (ret) {
+ free(buf);
+ return ret;
+ }
+ } while (end < s->len);
+
+ free(buf);
+ return 0;
+}
+#else
+static int sparse_file_read_hole(struct sparse_file* s __unused, int fd __unused) {
+ return -ENOTSUP;
+}
+#endif
+
+int sparse_file_read(struct sparse_file* s, int fd, enum sparse_read_mode mode, bool crc) {
+ if (crc && mode != SPARSE_READ_MODE_SPARSE) {
return -EINVAL;
}
- if (sparse) {
- SparseFileFdSource source(fd);
- return sparse_file_read_sparse(s, &source, crc);
- } else {
- return sparse_file_read_normal(s, fd);
+ switch (mode) {
+ case SPARSE_READ_MODE_SPARSE: {
+ SparseFileFdSource source(fd);
+ return sparse_file_read_sparse(s, &source, crc);
+ }
+ case SPARSE_READ_MODE_NORMAL:
+ return sparse_file_read_normal(s, fd);
+ case SPARSE_READ_MODE_HOLE:
+ return sparse_file_read_hole(s, fd);
+ default:
+ return -EINVAL;
}
}
diff --git a/libusbhost/Android.bp b/libusbhost/Android.bp
index 3883317..9ae73d0 100644
--- a/libusbhost/Android.bp
+++ b/libusbhost/Android.bp
@@ -30,11 +30,9 @@
export_include_dirs: ["include"],
target: {
android: {
- cflags: [
- "-g",
- "-DUSE_LIBLOG",
- ],
+ header_libs: ["jni_headers"],
shared_libs: ["liblog"],
+ srcs: ["usbhost_jni.cpp"],
},
darwin: {
enabled: false,
diff --git a/libusbhost/include/usbhost/usbhost.h b/libusbhost/include/usbhost/usbhost.h
index 7e62542..01cd68b 100644
--- a/libusbhost/include/usbhost/usbhost.h
+++ b/libusbhost/include/usbhost/usbhost.h
@@ -21,6 +21,7 @@
extern "C" {
#endif
+#include <stddef.h>
#include <stdint.h>
#include <linux/version.h>
diff --git a/libusbhost/include/usbhost/usbhost_jni.h b/libusbhost/include/usbhost/usbhost_jni.h
new file mode 100644
index 0000000..4885d45
--- /dev/null
+++ b/libusbhost/include/usbhost/usbhost_jni.h
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 2022 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 <jni.h>
+
+/**
+ * Reads USB descriptors from `fd`.
+ *
+ * Returns a byte[] on success,
+ * or returns NULL and logs an appropriate error on failure.
+ */
+jbyteArray usb_jni_read_descriptors(JNIEnv* env, int fd);
diff --git a/libusbhost/usbhost.c b/libusbhost/usbhost.c
index 3bed0e3..d8f15cd 100644
--- a/libusbhost/usbhost.c
+++ b/libusbhost/usbhost.c
@@ -18,20 +18,9 @@
#define _GNU_SOURCE
#endif
-// #define DEBUG 1
-#if DEBUG
+#include <usbhost/usbhost.h>
-#ifdef USE_LIBLOG
-#define LOG_TAG "usbhost"
-#include "log/log.h"
-#define D ALOGD
-#else
-#define D printf
-#endif
-
-#else
-#define D(...)
-#endif
+#include "usbhost_private.h"
#include <stdio.h>
#include <stdlib.h>
@@ -48,12 +37,19 @@
#include <errno.h>
#include <ctype.h>
#include <poll.h>
-#include <pthread.h>
#include <linux/usbdevice_fs.h>
-#include <asm/byteorder.h>
-#include "usbhost/usbhost.h"
+// #define DEBUG 1
+#if defined(DEBUG)
+#if defined(__BIONIC__)
+#define D ALOGD
+#else
+#define D printf
+#endif
+#else
+#define D(...)
+#endif
#define DEV_DIR "/dev"
#define DEV_BUS_DIR DEV_DIR "/bus"
@@ -76,8 +72,6 @@
int wddbus;
};
-#define MAX_DESCRIPTORS_LENGTH 4096
-
struct usb_device {
char dev_name[64];
unsigned char desc[MAX_DESCRIPTORS_LENGTH];
diff --git a/libusbhost/usbhost_jni.cpp b/libusbhost/usbhost_jni.cpp
new file mode 100644
index 0000000..0da83dc
--- /dev/null
+++ b/libusbhost/usbhost_jni.cpp
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2022 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 <usbhost/usbhost_jni.h>
+
+#include "usbhost_private.h"
+
+#include <errno.h>
+#include <string.h>
+#include <unistd.h>
+
+jbyteArray usb_jni_read_descriptors(JNIEnv* env, int fd) {
+ if (TEMP_FAILURE_RETRY(lseek(fd, 0, SEEK_SET)) == -1) {
+ ALOGE("usb_jni_read_descriptors(%d): lseek() failed: %s", fd, strerror(errno));
+ return NULL;
+ }
+
+ jbyte buf[MAX_DESCRIPTORS_LENGTH];
+ ssize_t n = TEMP_FAILURE_RETRY(read(fd, buf, sizeof(buf)));
+ if (n == -1) {
+ ALOGE("usb_jni_read_descriptors: read failed: %s", strerror(errno));
+ return NULL;
+ }
+
+ jbyteArray result = env->NewByteArray(n);
+ if (result) env->SetByteArrayRegion(result, 0, n, buf);
+ return result;
+}
diff --git a/libusbhost/usbhost_private.h b/libusbhost/usbhost_private.h
new file mode 100644
index 0000000..72d7938
--- /dev/null
+++ b/libusbhost/usbhost_private.h
@@ -0,0 +1,25 @@
+/*
+ * Copyright (C) 2022 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
+
+#define LOG_TAG "usbhost"
+#include <log/log.h>
+
+// Somewhat arbitrary: Sony has reported needing more than 4KiB (but less
+// than 8KiB), and some frameworks code had 16KiB without any explanation,
+// so we went with the largest of those.
+#define MAX_DESCRIPTORS_LENGTH (16 * 1024)
diff --git a/rootdir/init.rc b/rootdir/init.rc
index cd73498..c4c9eca 100644
--- a/rootdir/init.rc
+++ b/rootdir/init.rc
@@ -142,11 +142,21 @@
chown system system /dev/stune/background/tasks
chown system system /dev/stune/top-app/tasks
chown system system /dev/stune/rt/tasks
+ chown system system /dev/stune/cgroup.procs
+ chown system system /dev/stune/foreground/cgroup.procs
+ chown system system /dev/stune/background/cgroup.procs
+ chown system system /dev/stune/top-app/cgroup.procs
+ chown system system /dev/stune/rt/cgroup.procs
chmod 0664 /dev/stune/tasks
chmod 0664 /dev/stune/foreground/tasks
chmod 0664 /dev/stune/background/tasks
chmod 0664 /dev/stune/top-app/tasks
chmod 0664 /dev/stune/rt/tasks
+ chmod 0664 /dev/stune/cgroup.procs
+ chmod 0664 /dev/stune/foreground/cgroup.procs
+ chmod 0664 /dev/stune/background/cgroup.procs
+ chmod 0664 /dev/stune/top-app/cgroup.procs
+ chmod 0664 /dev/stune/rt/cgroup.procs
# cpuctl hierarchy for devices using utilclamp
mkdir /dev/cpuctl/foreground
@@ -172,6 +182,14 @@
chown system system /dev/cpuctl/system/tasks
chown system system /dev/cpuctl/system-background/tasks
chown system system /dev/cpuctl/dex2oat/tasks
+ chown system system /dev/cpuctl/cgroup.procs
+ chown system system /dev/cpuctl/foreground/cgroup.procs
+ chown system system /dev/cpuctl/background/cgroup.procs
+ chown system system /dev/cpuctl/top-app/cgroup.procs
+ chown system system /dev/cpuctl/rt/cgroup.procs
+ chown system system /dev/cpuctl/system/cgroup.procs
+ chown system system /dev/cpuctl/system-background/cgroup.procs
+ chown system system /dev/cpuctl/dex2oat/cgroup.procs
chmod 0664 /dev/cpuctl/tasks
chmod 0664 /dev/cpuctl/foreground/tasks
chmod 0664 /dev/cpuctl/background/tasks
@@ -180,12 +198,22 @@
chmod 0664 /dev/cpuctl/system/tasks
chmod 0664 /dev/cpuctl/system-background/tasks
chmod 0664 /dev/cpuctl/dex2oat/tasks
+ chmod 0664 /dev/cpuctl/cgroup.procs
+ chmod 0664 /dev/cpuctl/foreground/cgroup.procs
+ chmod 0664 /dev/cpuctl/background/cgroup.procs
+ chmod 0664 /dev/cpuctl/top-app/cgroup.procs
+ chmod 0664 /dev/cpuctl/rt/cgroup.procs
+ chmod 0664 /dev/cpuctl/system/cgroup.procs
+ chmod 0664 /dev/cpuctl/system-background/cgroup.procs
+ chmod 0664 /dev/cpuctl/dex2oat/cgroup.procs
# Create a cpu group for NNAPI HAL processes
mkdir /dev/cpuctl/nnapi-hal
chown system system /dev/cpuctl/nnapi-hal
chown system system /dev/cpuctl/nnapi-hal/tasks
+ chown system system /dev/cpuctl/nnapi-hal/cgroup.procs
chmod 0664 /dev/cpuctl/nnapi-hal/tasks
+ chmod 0664 /dev/cpuctl/nnapi-hal/cgroup.procs
write /dev/cpuctl/nnapi-hal/cpu.uclamp.min 1
write /dev/cpuctl/nnapi-hal/cpu.uclamp.latency_sensitive 1
@@ -193,19 +221,25 @@
mkdir /dev/cpuctl/camera-daemon
chown system system /dev/cpuctl/camera-daemon
chown system system /dev/cpuctl/camera-daemon/tasks
+ chown system system /dev/cpuctl/camera-daemon/cgroup.procs
chmod 0664 /dev/cpuctl/camera-daemon/tasks
+ chmod 0664 /dev/cpuctl/camera-daemon/cgroup.procs
# Create an stune group for camera-specific processes
mkdir /dev/stune/camera-daemon
chown system system /dev/stune/camera-daemon
chown system system /dev/stune/camera-daemon/tasks
+ chown system system /dev/stune/camera-daemon/cgroup.procs
chmod 0664 /dev/stune/camera-daemon/tasks
+ chmod 0664 /dev/stune/camera-daemon/cgroup.procs
# Create an stune group for NNAPI HAL processes
mkdir /dev/stune/nnapi-hal
chown system system /dev/stune/nnapi-hal
chown system system /dev/stune/nnapi-hal/tasks
+ chown system system /dev/stune/nnapi-hal/cgroup.procs
chmod 0664 /dev/stune/nnapi-hal/tasks
+ chmod 0664 /dev/stune/nnapi-hal/cgroup.procs
write /dev/stune/nnapi-hal/schedtune.boost 1
write /dev/stune/nnapi-hal/schedtune.prefer_idle 1
@@ -217,8 +251,12 @@
chown system system /dev/blkio/background
chown system system /dev/blkio/tasks
chown system system /dev/blkio/background/tasks
+ chown system system /dev/blkio/cgroup.procs
+ chown system system /dev/blkio/background/cgroup.procs
chmod 0664 /dev/blkio/tasks
chmod 0664 /dev/blkio/background/tasks
+ chmod 0664 /dev/blkio/cgroup.procs
+ chmod 0664 /dev/blkio/background/cgroup.procs
write /dev/blkio/blkio.weight 1000
write /dev/blkio/background/blkio.weight 200
write /dev/blkio/background/blkio.bfq.weight 10
@@ -367,6 +405,13 @@
chown system system /dev/cpuset/top-app/tasks
chown system system /dev/cpuset/restricted/tasks
chown system system /dev/cpuset/camera-daemon/tasks
+ chown system system /dev/cpuset/cgroup.procs
+ chown system system /dev/cpuset/foreground/cgroup.procs
+ chown system system /dev/cpuset/background/cgroup.procs
+ chown system system /dev/cpuset/system-background/cgroup.procs
+ chown system system /dev/cpuset/top-app/cgroup.procs
+ chown system system /dev/cpuset/restricted/cgroup.procs
+ chown system system /dev/cpuset/camera-daemon/cgroup.procs
# set system-background to 0775 so SurfaceFlinger can touch it
chmod 0775 /dev/cpuset/system-background
@@ -378,6 +423,13 @@
chmod 0664 /dev/cpuset/restricted/tasks
chmod 0664 /dev/cpuset/tasks
chmod 0664 /dev/cpuset/camera-daemon/tasks
+ chmod 0664 /dev/cpuset/foreground/cgroup.procs
+ chmod 0664 /dev/cpuset/background/cgroup.procs
+ chmod 0664 /dev/cpuset/system-background/cgroup.procs
+ chmod 0664 /dev/cpuset/top-app/cgroup.procs
+ chmod 0664 /dev/cpuset/restricted/cgroup.procs
+ chmod 0664 /dev/cpuset/cgroup.procs
+ chmod 0664 /dev/cpuset/camera-daemon/cgroup.procs
# make the PSI monitor accessible to others
chown system system /proc/pressure/memory