Merge "Add feature flag for TelephonyManager#get/setAllowedCarriers"
diff --git a/cmds/dumpstate/Android.mk b/cmds/dumpstate/Android.mk
index e478651..daeebc4 100644
--- a/cmds/dumpstate/Android.mk
+++ b/cmds/dumpstate/Android.mk
@@ -10,7 +10,7 @@
LOCAL_MODULE := dumpstate
-LOCAL_SHARED_LIBRARIES := libcutils liblog libselinux libbase libhardware_legacy
+LOCAL_SHARED_LIBRARIES := libcutils libdebuggerd_client liblog libselinux libbase libhardware_legacy
# ZipArchive support, the order matters here to get all symbols.
LOCAL_STATIC_LIBRARIES := libziparchive libz libcrypto_static
LOCAL_HAL_STATIC_LIBRARIES := libdumpstate
diff --git a/cmds/dumpstate/utils.cpp b/cmds/dumpstate/utils.cpp
index afb52e7..4ac5b67 100644
--- a/cmds/dumpstate/utils.cpp
+++ b/cmds/dumpstate/utils.cpp
@@ -40,9 +40,9 @@
#include <vector>
#include <android-base/file.h>
-#include <cutils/debugger.h>
#include <cutils/properties.h>
#include <cutils/sockets.h>
+#include <debuggerd/client.h>
#include <log/log.h>
#include <private/android_filesystem_config.h>
@@ -1021,8 +1021,10 @@
}
/* create a new, empty traces.txt file to receive stack dumps */
- int fd = TEMP_FAILURE_RETRY(open(traces_path, O_CREAT | O_WRONLY | O_TRUNC | O_NOFOLLOW | O_CLOEXEC,
- 0666)); /* -rw-rw-rw- */
+ int fd = TEMP_FAILURE_RETRY(
+ open(traces_path,
+ O_CREAT | O_WRONLY | O_APPEND | O_TRUNC | O_NOFOLLOW | O_CLOEXEC,
+ 0666)); /* -rw-rw-rw- */
if (fd < 0) {
MYLOGE("%s: %s\n", traces_path, strerror(errno));
return NULL;
diff --git a/cmds/installd/Android.bp b/cmds/installd/Android.bp
index 93174bf..33db6db 100644
--- a/cmds/installd/Android.bp
+++ b/cmds/installd/Android.bp
@@ -6,6 +6,8 @@
"-Werror",
],
srcs: [
+ "CacheItem.cpp",
+ "CacheTracker.cpp",
"InstalldNativeService.cpp",
"dexopt.cpp",
"globals.cpp",
diff --git a/cmds/installd/CacheItem.cpp b/cmds/installd/CacheItem.cpp
new file mode 100644
index 0000000..d1bdded
--- /dev/null
+++ b/cmds/installd/CacheItem.cpp
@@ -0,0 +1,71 @@
+/*
+ * Copyright (C) 2017 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 "CacheItem.h"
+
+#include <stdint.h>
+#include <inttypes.h>
+
+#include <android-base/logging.h>
+#include <android-base/stringprintf.h>
+
+#include "utils.h"
+
+using android::base::StringPrintf;
+
+namespace android {
+namespace installd {
+
+CacheItem::CacheItem(const std::shared_ptr<CacheItem>& parent, FTSENT* p) : mParent(parent) {
+ level = p->fts_level;
+ directory = S_ISDIR(p->fts_statp->st_mode);
+ size = p->fts_statp->st_blocks * 512;
+ modified = p->fts_statp->st_mtime;
+ mName = p->fts_path;
+}
+
+CacheItem::~CacheItem() {
+}
+
+std::string CacheItem::toString() {
+ return StringPrintf("%s size=%" PRId64 " mod=%ld", buildPath().c_str(), size, modified);
+}
+
+std::string CacheItem::buildPath() {
+ std::string res = mName;
+ std::shared_ptr<CacheItem> parent = mParent;
+ while (parent) {
+ res.insert(0, parent->mName);
+ parent = parent->mParent;
+ }
+ return res;
+}
+
+int CacheItem::purge() {
+ auto path = buildPath();
+ if (directory) {
+ return delete_dir_contents_and_dir(path, true);
+ } else {
+ int res = unlink(path.c_str());
+ if (res != 0) {
+ PLOG(WARNING) << "Failed to unlink " << path;
+ }
+ return res;
+ }
+}
+
+} // namespace installd
+} // namespace android
diff --git a/cmds/installd/CacheItem.h b/cmds/installd/CacheItem.h
new file mode 100644
index 0000000..bec8bc8
--- /dev/null
+++ b/cmds/installd/CacheItem.h
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2017 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.
+ */
+
+#ifndef ANDROID_INSTALLD_CACHE_ITEM_H
+#define ANDROID_INSTALLD_CACHE_ITEM_H
+
+#include <memory>
+#include <string>
+
+#include <fts.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include <android-base/macros.h>
+
+namespace android {
+namespace installd {
+
+/**
+ * Single cache item that can be purged to free up space. This may be an
+ * isolated file, or an entire directory tree that should be atomically
+ * deleted.
+ */
+class CacheItem {
+public:
+ CacheItem(const std::shared_ptr<CacheItem>& parent, FTSENT* p);
+ ~CacheItem();
+
+ std::string toString();
+ std::string buildPath();
+
+ int purge();
+
+ short level;
+ bool directory;
+ int64_t size;
+ time_t modified;
+
+private:
+ std::shared_ptr<CacheItem> mParent;
+ std::string mName;
+
+ DISALLOW_COPY_AND_ASSIGN(CacheItem);
+};
+
+} // namespace installd
+} // namespace android
+
+#endif // ANDROID_INSTALLD_CACHE_ITEM_H
diff --git a/cmds/installd/CacheTracker.cpp b/cmds/installd/CacheTracker.cpp
new file mode 100644
index 0000000..23c4330
--- /dev/null
+++ b/cmds/installd/CacheTracker.cpp
@@ -0,0 +1,162 @@
+/*
+ * Copyright (C) 2017 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.
+ */
+
+#define ATRACE_TAG ATRACE_TAG_PACKAGE_MANAGER
+
+#include "CacheTracker.h"
+
+#include <fts.h>
+#include <sys/quota.h>
+#include <utils/Trace.h>
+
+#include <android-base/logging.h>
+#include <android-base/stringprintf.h>
+
+#include "utils.h"
+
+using android::base::StringPrintf;
+
+namespace android {
+namespace installd {
+
+CacheTracker::CacheTracker(userid_t userId, appid_t appId, const std::string& quotaDevice) :
+ cacheUsed(0), cacheQuota(0), mUserId(userId), mAppId(appId), mQuotaDevice(quotaDevice),
+ mItemsLoaded(false) {
+}
+
+CacheTracker::~CacheTracker() {
+}
+
+std::string CacheTracker::toString() {
+ return StringPrintf("UID=%d used=%" PRId64 " quota=%" PRId64 " ratio=%d",
+ multiuser_get_uid(mUserId, mAppId), cacheUsed, cacheQuota, getCacheRatio());
+}
+
+void CacheTracker::addDataPath(const std::string& dataPath) {
+ mDataPaths.push_back(dataPath);
+}
+
+void CacheTracker::loadStats() {
+ int cacheGid = multiuser_get_cache_gid(mUserId, mAppId);
+ if (cacheGid != -1 && !mQuotaDevice.empty()) {
+ ATRACE_BEGIN("loadStats quota");
+ struct dqblk dq;
+ if (quotactl(QCMD(Q_GETQUOTA, GRPQUOTA), mQuotaDevice.c_str(), cacheGid,
+ reinterpret_cast<char*>(&dq)) != 0) {
+ ATRACE_END();
+ if (errno != ESRCH) {
+ PLOG(ERROR) << "Failed to quotactl " << mQuotaDevice << " for GID " << cacheGid;
+ }
+ } else {
+ cacheUsed = dq.dqb_curspace;
+ ATRACE_END();
+ return;
+ }
+ }
+
+ ATRACE_BEGIN("loadStats tree");
+ cacheUsed = 0;
+ for (auto path : mDataPaths) {
+ auto cachePath = read_path_inode(path, "cache", kXattrInodeCache);
+ auto codeCachePath = read_path_inode(path, "code_cache", kXattrInodeCodeCache);
+ calculate_tree_size(cachePath, &cacheUsed);
+ calculate_tree_size(codeCachePath, &cacheUsed);
+ }
+ ATRACE_END();
+}
+
+void CacheTracker::loadItemsFrom(const std::string& path) {
+ FTS *fts;
+ FTSENT *p;
+ char *argv[] = { (char*) path.c_str(), nullptr };
+ if (!(fts = fts_open(argv, FTS_PHYSICAL | FTS_XDEV, NULL))) {
+ PLOG(WARNING) << "Failed to fts_open " << path;
+ return;
+ }
+ // TODO: add support for "user.atomic" and "user.tombstone" xattrs
+ while ((p = fts_read(fts)) != NULL) {
+ switch (p->fts_info) {
+ case FTS_D:
+ // Track the newest mtime of anything inside so we consider
+ // deleting the directory last
+ p->fts_number = p->fts_statp->st_mtime;
+ break;
+ case FTS_DP:
+ p->fts_statp->st_mtime = p->fts_number;
+
+ // Ignore the actual top-level cache directories
+ if (p->fts_level == 0) break;
+ case FTS_DEFAULT:
+ case FTS_F:
+ case FTS_SL:
+ case FTS_SLNONE:
+ // TODO: optimize path memory footprint
+ items.push_back(std::shared_ptr<CacheItem>(new CacheItem(nullptr, p)));
+
+ // Track the newest modified item under this tree
+ p->fts_parent->fts_number =
+ std::max(p->fts_parent->fts_number, p->fts_statp->st_mtime);
+ break;
+ }
+ }
+ fts_close(fts);
+}
+
+void CacheTracker::loadItems() {
+ items.clear();
+
+ ATRACE_BEGIN("loadItems");
+ for (auto path : mDataPaths) {
+ loadItemsFrom(read_path_inode(path, "cache", kXattrInodeCache));
+ loadItemsFrom(read_path_inode(path, "code_cache", kXattrInodeCodeCache));
+ }
+ ATRACE_END();
+
+ ATRACE_BEGIN("sortItems");
+ auto cmp = [](std::shared_ptr<CacheItem> left, std::shared_ptr<CacheItem> right) {
+ // TODO: sort dotfiles last
+ // TODO: sort code_cache last
+ if (left->modified != right->modified) {
+ return (left->modified > right->modified);
+ }
+ if (left->level != right->level) {
+ return (left->level < right->level);
+ }
+ return left->directory;
+ };
+ std::sort(items.begin(), items.end(), cmp);
+ ATRACE_END();
+}
+
+void CacheTracker::ensureItems() {
+ if (mItemsLoaded) {
+ return;
+ } else {
+ loadItems();
+ mItemsLoaded = true;
+ }
+}
+
+int CacheTracker::getCacheRatio() {
+ if (cacheQuota == 0) {
+ return 0;
+ } else {
+ return (cacheUsed * 10000) / cacheQuota;
+ }
+}
+
+} // namespace installd
+} // namespace android
diff --git a/cmds/installd/CacheTracker.h b/cmds/installd/CacheTracker.h
new file mode 100644
index 0000000..91692d7
--- /dev/null
+++ b/cmds/installd/CacheTracker.h
@@ -0,0 +1,77 @@
+/*
+ * Copyright (C) 2017 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.
+ */
+
+#ifndef ANDROID_INSTALLD_CACHE_TRACKER_H
+#define ANDROID_INSTALLD_CACHE_TRACKER_H
+
+#include <memory>
+#include <string>
+#include <queue>
+
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include <android-base/macros.h>
+#include <cutils/multiuser.h>
+
+#include "CacheItem.h"
+
+namespace android {
+namespace installd {
+
+/**
+ * Cache tracker for a single UID. Each tracker is used in two modes: first
+ * for loading lightweight "stats", and then by loading detailed "items"
+ * which can then be purged to free up space.
+ */
+class CacheTracker {
+public:
+ CacheTracker(userid_t userId, appid_t appId, const std::string& quotaDevice);
+ ~CacheTracker();
+
+ std::string toString();
+
+ void addDataPath(const std::string& dataPath);
+
+ void loadStats();
+ void loadItems();
+
+ void ensureItems();
+
+ int getCacheRatio();
+
+ int64_t cacheUsed;
+ int64_t cacheQuota;
+
+ std::vector<std::shared_ptr<CacheItem>> items;
+
+private:
+ userid_t mUserId;
+ appid_t mAppId;
+ std::string mQuotaDevice;
+ bool mItemsLoaded;
+
+ std::vector<std::string> mDataPaths;
+
+ void loadItemsFrom(const std::string& path);
+
+ DISALLOW_COPY_AND_ASSIGN(CacheTracker);
+};
+
+} // namespace installd
+} // namespace android
+
+#endif // ANDROID_INSTALLD_CACHE_TRACKER_H
diff --git a/cmds/installd/InstalldNativeService.cpp b/cmds/installd/InstalldNativeService.cpp
index 7fe2e19..914eaae 100644
--- a/cmds/installd/InstalldNativeService.cpp
+++ b/cmds/installd/InstalldNativeService.cpp
@@ -16,6 +16,8 @@
#include "InstalldNativeService.h"
+#define ATRACE_TAG ATRACE_TAG_PACKAGE_MANAGER
+
#include <errno.h>
#include <inttypes.h>
#include <fstream>
@@ -46,6 +48,7 @@
#include <private/android_filesystem_config.h>
#include <selinux/android.h>
#include <system/thread_defs.h>
+#include <utils/Trace.h>
#include "dexopt.h"
#include "globals.h"
@@ -53,6 +56,7 @@
#include "otapreopt_utils.h"
#include "utils.h"
+#include "CacheTracker.h"
#include "MatchExtensionGen.h"
#ifndef LOG_TAG
@@ -60,6 +64,7 @@
#endif
using android::base::StringPrintf;
+using std::endl;
namespace android {
namespace installd {
@@ -82,6 +87,8 @@
static constexpr int FLAG_CLEAR_CACHE_ONLY = 1 << 8;
static constexpr int FLAG_CLEAR_CODE_CACHE_ONLY = 1 << 9;
static constexpr int FLAG_USE_QUOTA = 1 << 12;
+static constexpr int FLAG_FREE_CACHE_V2 = 1 << 13;
+static constexpr int FLAG_FREE_CACHE_NOOP = 1 << 14;
#define MIN_RESTRICTED_HOME_SDK_VERSION 24 // > M
namespace {
@@ -188,15 +195,29 @@
}
status_t InstalldNativeService::dump(int fd, const Vector<String16> & /* args */) {
+ auto out = std::fstream(StringPrintf("/proc/self/fd/%d", fd));
const binder::Status dump_permission = checkPermission(kDump);
if (!dump_permission.isOk()) {
- const String8 msg(dump_permission.toString8());
- write(fd, msg.string(), msg.size());
+ out << dump_permission.toString8() << endl;
return PERMISSION_DENIED;
}
+ std::lock_guard<std::recursive_mutex> lock(mLock);
- std::string msg = "installd is happy\n";
- write(fd, msg.c_str(), strlen(msg.c_str()));
+ out << "installd is happy!" << endl;
+
+ out << endl << "Devices with quota support:" << endl;
+ for (const auto& n : mQuotaDevices) {
+ out << " " << n.first << " = " << n.second << endl;
+ }
+
+ out << endl << "Per-UID cache quotas:" << endl;
+ for (const auto& n : mCacheQuotas) {
+ out << " " << n.first << " = " << n.second << endl;
+ }
+
+ out << endl;
+ out.flush();
+
return NO_ERROR;
}
@@ -287,12 +308,13 @@
}
}
+ mode_t actual_mode = st.st_mode & (S_IRWXU | S_IRWXG | S_IRWXO | S_ISGID);
if (st.st_uid != uid) {
// Mismatched UID is real trouble; we can't recover
LOG(ERROR) << "Mismatched UID at " << path << ": found " << st.st_uid
<< " but expected " << uid;
return -1;
- } else if (st.st_gid == gid && st.st_mode == target_mode) {
+ } else if (st.st_gid == gid && actual_mode == target_mode) {
// Everything looks good!
return 0;
}
@@ -336,6 +358,7 @@
ENFORCE_UID(AID_SYSTEM);
CHECK_ARGUMENT_UUID(uuid);
CHECK_ARGUMENT_PACKAGE_NAME(packageName);
+ std::lock_guard<std::recursive_mutex> lock(mLock);
const char* uuid_ = uuid ? uuid->c_str() : nullptr;
const char* pkgname = packageName.c_str();
@@ -343,10 +366,15 @@
// Assume invalid inode unless filled in below
if (_aidl_return != nullptr) *_aidl_return = -1;
- uid_t uid = multiuser_get_uid(userId, appId);
- gid_t cacheGid = multiuser_get_cache_gid(userId, appId);
+ int32_t uid = multiuser_get_uid(userId, appId);
+ int32_t cacheGid = multiuser_get_cache_gid(userId, appId);
mode_t targetMode = targetSdkVersion >= MIN_RESTRICTED_HOME_SDK_VERSION ? 0700 : 0751;
+ // If UID doesn't have a specific cache GID, use UID value
+ if (cacheGid == -1) {
+ cacheGid = uid;
+ }
+
if (flags & FLAG_STORAGE_CE) {
auto path = create_data_user_ce_package_path(uuid_, userId, pkgname);
bool existing = (access(path.c_str(), F_OK) == 0);
@@ -422,6 +450,7 @@
ENFORCE_UID(AID_SYSTEM);
CHECK_ARGUMENT_UUID(uuid);
CHECK_ARGUMENT_PACKAGE_NAME(packageName);
+ std::lock_guard<std::recursive_mutex> lock(mLock);
const char* uuid_ = uuid ? uuid->c_str() : nullptr;
const char* pkgname = packageName.c_str();
@@ -464,6 +493,7 @@
binder::Status InstalldNativeService::clearAppProfiles(const std::string& packageName) {
ENFORCE_UID(AID_SYSTEM);
CHECK_ARGUMENT_PACKAGE_NAME(packageName);
+ std::lock_guard<std::recursive_mutex> lock(mLock);
const char* pkgname = packageName.c_str();
binder::Status res = ok();
@@ -481,6 +511,7 @@
ENFORCE_UID(AID_SYSTEM);
CHECK_ARGUMENT_UUID(uuid);
CHECK_ARGUMENT_PACKAGE_NAME(packageName);
+ std::lock_guard<std::recursive_mutex> lock(mLock);
const char* uuid_ = uuid ? uuid->c_str() : nullptr;
const char* pkgname = packageName.c_str();
@@ -540,6 +571,7 @@
binder::Status InstalldNativeService::destroyAppProfiles(const std::string& packageName) {
ENFORCE_UID(AID_SYSTEM);
CHECK_ARGUMENT_PACKAGE_NAME(packageName);
+ std::lock_guard<std::recursive_mutex> lock(mLock);
const char* pkgname = packageName.c_str();
binder::Status res = ok();
@@ -560,6 +592,7 @@
ENFORCE_UID(AID_SYSTEM);
CHECK_ARGUMENT_UUID(uuid);
CHECK_ARGUMENT_PACKAGE_NAME(packageName);
+ std::lock_guard<std::recursive_mutex> lock(mLock);
const char* uuid_ = uuid ? uuid->c_str() : nullptr;
const char* pkgname = packageName.c_str();
@@ -593,6 +626,7 @@
CHECK_ARGUMENT_UUID(fromUuid);
CHECK_ARGUMENT_UUID(toUuid);
CHECK_ARGUMENT_PACKAGE_NAME(packageName);
+ std::lock_guard<std::recursive_mutex> lock(mLock);
const char* from_uuid = fromUuid ? fromUuid->c_str() : nullptr;
const char* to_uuid = toUuid ? toUuid->c_str() : nullptr;
@@ -727,6 +761,7 @@
int32_t userId, int32_t userSerial ATTRIBUTE_UNUSED, int32_t flags) {
ENFORCE_UID(AID_SYSTEM);
CHECK_ARGUMENT_UUID(uuid);
+ std::lock_guard<std::recursive_mutex> lock(mLock);
const char* uuid_ = uuid ? uuid->c_str() : nullptr;
if (flags & FLAG_STORAGE_DE) {
@@ -743,6 +778,7 @@
int32_t userId, int32_t flags) {
ENFORCE_UID(AID_SYSTEM);
CHECK_ARGUMENT_UUID(uuid);
+ std::lock_guard<std::recursive_mutex> lock(mLock);
const char* uuid_ = uuid ? uuid->c_str() : nullptr;
binder::Status res = ok();
@@ -783,51 +819,172 @@
* when just reading from the cache, which is pretty awful.
*/
binder::Status InstalldNativeService::freeCache(const std::unique_ptr<std::string>& uuid,
- int64_t freeStorageSize) {
+ int64_t freeStorageSize, int32_t flags) {
ENFORCE_UID(AID_SYSTEM);
CHECK_ARGUMENT_UUID(uuid);
+ std::lock_guard<std::recursive_mutex> lock(mLock);
+
+ // TODO: remove this once framework is more robust
+ invalidateMounts();
const char* uuid_ = uuid ? uuid->c_str() : nullptr;
- cache_t* cache;
- int64_t avail;
-
auto data_path = create_data_path(uuid_);
+ auto device = findQuotaDeviceForUuid(uuid);
+ auto noop = (flags & FLAG_FREE_CACHE_NOOP);
- avail = data_disk_free(data_path);
- if (avail < 0) {
+ int64_t free = data_disk_free(data_path);
+ int64_t needed = freeStorageSize - free;
+ if (free < 0) {
return error("Failed to determine free space for " + data_path);
- }
-
- ALOGI("free_cache(%" PRId64 ") avail %" PRId64 "\n", freeStorageSize, avail);
- if (avail >= freeStorageSize) {
+ } else if (free >= freeStorageSize) {
return ok();
}
- cache = start_cache_collection();
+ LOG(DEBUG) << "Found " << data_path << " with " << free << " free; caller requested "
+ << freeStorageSize;
- auto users = get_known_users(uuid_);
- for (auto user : users) {
- add_cache_files(cache, create_data_user_ce_path(uuid_, user));
- add_cache_files(cache, create_data_user_de_path(uuid_, user));
- add_cache_files(cache,
- StringPrintf("%s/Android/data", create_data_media_path(uuid_, user).c_str()));
+ if (flags & FLAG_FREE_CACHE_V2) {
+ // This new cache strategy fairly removes files from UIDs by deleting
+ // files from the UIDs which are most over their allocated quota
+
+ // 1. Create trackers for every known UID
+ ATRACE_BEGIN("create");
+ std::unordered_map<uid_t, std::shared_ptr<CacheTracker>> trackers;
+ for (auto user : get_known_users(uuid_)) {
+ FTS *fts;
+ FTSENT *p;
+ char *argv[] = {
+ (char*) create_data_user_ce_path(uuid_, user).c_str(),
+ (char*) create_data_user_de_path(uuid_, user).c_str(),
+ nullptr
+ };
+ if (!(fts = fts_open(argv, FTS_PHYSICAL | FTS_XDEV, NULL))) {
+ return error("Failed to fts_open");
+ }
+ while ((p = fts_read(fts)) != NULL) {
+ if (p->fts_info == FTS_D && p->fts_level == 1) {
+ uid_t uid = p->fts_statp->st_uid;
+ auto search = trackers.find(uid);
+ if (search != trackers.end()) {
+ search->second->addDataPath(p->fts_path);
+ } else {
+ auto tracker = std::shared_ptr<CacheTracker>(new CacheTracker(
+ multiuser_get_user_id(uid), multiuser_get_app_id(uid), device));
+ tracker->addDataPath(p->fts_path);
+ tracker->cacheQuota = mCacheQuotas[uid];
+ if (tracker->cacheQuota == 0) {
+ LOG(WARNING) << "UID " << uid << " has no cache quota; assuming 64MB";
+ tracker->cacheQuota = 67108864;
+ }
+ trackers[uid] = tracker;
+ }
+ fts_set(fts, p, FTS_SKIP);
+ }
+ }
+ fts_close(fts);
+ }
+ ATRACE_END();
+
+ // 2. Populate tracker stats and insert into priority queue
+ ATRACE_BEGIN("populate");
+ auto cmp = [](std::shared_ptr<CacheTracker> left, std::shared_ptr<CacheTracker> right) {
+ return (left->getCacheRatio() < right->getCacheRatio());
+ };
+ std::priority_queue<std::shared_ptr<CacheTracker>,
+ std::vector<std::shared_ptr<CacheTracker>>, decltype(cmp)> queue(cmp);
+ for (const auto& it : trackers) {
+ it.second->loadStats();
+ queue.push(it.second);
+ }
+ ATRACE_END();
+
+ // 3. Bounce across the queue, freeing items from whichever tracker is
+ // the most over their assigned quota
+ ATRACE_BEGIN("bounce");
+ std::shared_ptr<CacheTracker> active;
+ while (active || !queue.empty()) {
+ // Find the best tracker to work with; this might involve swapping
+ // if the active tracker is no longer the most over quota
+ bool nextBetter = active && !queue.empty()
+ && active->getCacheRatio() < queue.top()->getCacheRatio();
+ if (!active || nextBetter) {
+ if (active) {
+ // Current tracker still has items, so we'll consider it
+ // again later once it bubbles up to surface
+ queue.push(active);
+ }
+ active = queue.top(); queue.pop();
+ active->ensureItems();
+ continue;
+ }
+
+ // If no items remain, go find another tracker
+ if (active->items.empty()) {
+ active = nullptr;
+ continue;
+ } else {
+ auto item = active->items.back();
+ active->items.pop_back();
+
+ LOG(DEBUG) << "Purging " << item->toString() << " from " << active->toString();
+ if (!noop) {
+ item->purge();
+ }
+ active->cacheUsed -= item->size;
+ needed -= item->size;
+ }
+
+ // Verify that we're actually done before bailing, since sneaky
+ // apps might be using hardlinks
+ if (needed <= 0) {
+ free = data_disk_free(data_path);
+ needed = freeStorageSize - free;
+ if (needed <= 0) {
+ break;
+ } else {
+ LOG(WARNING) << "Expected to be done but still need " << needed;
+ }
+ }
+ }
+ ATRACE_END();
+
+ } else {
+ ATRACE_BEGIN("start");
+ cache_t* cache = start_cache_collection();
+ ATRACE_END();
+
+ ATRACE_BEGIN("add");
+ for (auto user : get_known_users(uuid_)) {
+ add_cache_files(cache, create_data_user_ce_path(uuid_, user));
+ add_cache_files(cache, create_data_user_de_path(uuid_, user));
+ add_cache_files(cache,
+ StringPrintf("%s/Android/data", create_data_media_path(uuid_, user).c_str()));
+ }
+ ATRACE_END();
+
+ ATRACE_BEGIN("clear");
+ clear_cache_files(data_path, cache, freeStorageSize);
+ ATRACE_END();
+
+ ATRACE_BEGIN("finish");
+ finish_cache_collection(cache);
+ ATRACE_END();
}
- clear_cache_files(data_path, cache, freeStorageSize);
- finish_cache_collection(cache);
-
- avail = data_disk_free(data_path);
- if (avail >= freeStorageSize) {
+ free = data_disk_free(data_path);
+ if (free >= freeStorageSize) {
return ok();
} else {
return error(StringPrintf("Failed to free up %" PRId64 " on %s; final free space %" PRId64,
- freeStorageSize, data_path.c_str(), avail));
+ freeStorageSize, data_path.c_str(), free));
}
}
binder::Status InstalldNativeService::rmdex(const std::string& codePath,
const std::string& instructionSet) {
ENFORCE_UID(AID_SYSTEM);
+ std::lock_guard<std::recursive_mutex> lock(mLock);
+
char dex_path[PKG_PATH_MAX];
const char* path = codePath.c_str();
@@ -870,30 +1027,8 @@
}
#endif
-static std::string findDeviceForUuid(const std::unique_ptr<std::string>& uuid) {
- auto path = create_data_path(uuid ? uuid->c_str() : nullptr);
- std::ifstream in("/proc/mounts");
- if (!in.is_open()) {
- PLOG(ERROR) << "Failed to read mounts";
- return "";
- }
- std::string source;
- std::string target;
- while (!in.eof()) {
- std::getline(in, source, ' ');
- std::getline(in, target, ' ');
- if (target == path) {
- return source;
- }
- // Skip to next line
- std::getline(in, source);
- }
- PLOG(ERROR) << "Failed to resolve block device for " << path;
- return "";
-}
-
static void collectQuotaStats(const std::string& device, int32_t userId,
- int32_t appId, struct stats* stats, struct stats* extStats ATTRIBUTE_UNUSED) {
+ int32_t appId, struct stats* stats, struct stats* extStats) {
if (device.empty()) return;
struct dqblk dq;
@@ -920,13 +1055,28 @@
}
} else {
#if MEASURE_DEBUG
- LOG(DEBUG) << "quotactl() for GID " << cacheGid << " " << dq.dqb_curspace;
+ LOG(DEBUG) << "quotactl() for GID " << cacheGid << " " << dq.dqb_curspace;
#endif
stats->cacheSize += dq.dqb_curspace;
}
}
- int sharedGid = multiuser_get_shared_app_gid(uid);
+ int extGid = multiuser_get_ext_gid(userId, appId);
+ if (extGid != -1) {
+ if (quotactl(QCMD(Q_GETQUOTA, GRPQUOTA), device.c_str(), extGid,
+ reinterpret_cast<char*>(&dq)) != 0) {
+ if (errno != ESRCH) {
+ PLOG(ERROR) << "Failed to quotactl " << device << " for GID " << extGid;
+ }
+ } else {
+#if MEASURE_DEBUG
+ LOG(DEBUG) << "quotactl() for GID " << extGid << " " << dq.dqb_curspace;
+#endif
+ extStats->dataSize += dq.dqb_curspace;
+ }
+ }
+
+ int sharedGid = multiuser_get_shared_gid(userId, appId);
if (sharedGid != -1) {
if (quotactl(QCMD(Q_GETQUOTA, GRPQUOTA), device.c_str(), sharedGid,
reinterpret_cast<char*>(&dq)) != 0) {
@@ -935,20 +1085,11 @@
}
} else {
#if MEASURE_DEBUG
- LOG(DEBUG) << "quotactl() for GID " << sharedGid << " " << dq.dqb_curspace;
+ LOG(DEBUG) << "quotactl() for GID " << sharedGid << " " << dq.dqb_curspace;
#endif
stats->codeSize += dq.dqb_curspace;
}
}
-
-#if MEASURE_EXTERNAL
- // TODO: measure using external GIDs
-#endif
-}
-
-static void collectQuotaStats(const std::unique_ptr<std::string>& uuid, int32_t userId,
- int32_t appId, struct stats* stats, struct stats* extStats) {
- collectQuotaStats(findDeviceForUuid(uuid), userId, appId, stats, extStats);
}
static void collectManualStats(const std::string& path, struct stats* stats) {
@@ -1034,6 +1175,40 @@
closedir(d);
}
+static void collectManualExternalStatsForUser(const std::string& path, struct stats* stats) {
+ FTS *fts;
+ FTSENT *p;
+ char *argv[] = { (char*) path.c_str(), nullptr };
+ if (!(fts = fts_open(argv, FTS_PHYSICAL | FTS_XDEV, NULL))) {
+ PLOG(ERROR) << "Failed to fts_open " << path;
+ return;
+ }
+ while ((p = fts_read(fts)) != NULL) {
+ switch (p->fts_info) {
+ case FTS_D:
+ if (p->fts_level == 4
+ && !strcmp(p->fts_name, "cache")
+ && !strcmp(p->fts_parent->fts_parent->fts_name, "data")
+ && !strcmp(p->fts_parent->fts_parent->fts_parent->fts_name, "Android")) {
+ p->fts_number = 1;
+ }
+ p->fts_number = p->fts_parent->fts_number;
+ // Fall through to count the directory
+ case FTS_DEFAULT:
+ case FTS_F:
+ case FTS_SL:
+ case FTS_SLNONE:
+ int64_t size = (p->fts_statp->st_blocks * 512);
+ if (p->fts_number == 1) {
+ stats->cacheSize += size;
+ }
+ stats->dataSize += size;
+ break;
+ }
+ }
+ fts_close(fts);
+}
+
binder::Status InstalldNativeService::getAppSize(const std::unique_ptr<std::string>& uuid,
const std::vector<std::string>& packageNames, int32_t userId, int32_t flags,
int32_t appId, const std::vector<int64_t>& ceDataInodes,
@@ -1043,6 +1218,7 @@
for (auto packageName : packageNames) {
CHECK_ARGUMENT_PACKAGE_NAME(packageName);
}
+ std::lock_guard<std::recursive_mutex> lock(mLock);
// When modifying this logic, always verify using tests:
// runtest -x frameworks/base/services/tests/servicestests/src/com/android/server/pm/InstallerTest.java -m testGetAppSize
@@ -1071,56 +1247,71 @@
const char* uuid_ = uuid ? uuid->c_str() : nullptr;
+ auto device = findQuotaDeviceForUuid(uuid);
+ if (device.empty()) {
+ flags &= ~FLAG_USE_QUOTA;
+ }
+
+ ATRACE_BEGIN("obb");
for (auto packageName : packageNames) {
auto obbCodePath = create_data_media_obb_path(uuid_, packageName.c_str());
calculate_tree_size(obbCodePath, &extStats.codeSize);
}
+ ATRACE_END();
if (flags & FLAG_USE_QUOTA && appId >= AID_APP_START) {
+ ATRACE_BEGIN("code");
for (auto codePath : codePaths) {
calculate_tree_size(codePath, &stats.codeSize, -1,
multiuser_get_shared_gid(userId, appId));
}
+ ATRACE_END();
- collectQuotaStats(uuid, userId, appId, &stats, &extStats);
+ ATRACE_BEGIN("quota");
+ collectQuotaStats(device, userId, appId, &stats, &extStats);
+ ATRACE_END();
} else {
+ ATRACE_BEGIN("code");
for (auto codePath : codePaths) {
calculate_tree_size(codePath, &stats.codeSize);
}
+ ATRACE_END();
for (size_t i = 0; i < packageNames.size(); i++) {
const char* pkgname = packageNames[i].c_str();
+ ATRACE_BEGIN("data");
auto cePath = create_data_user_ce_package_path(uuid_, userId, pkgname, ceDataInodes[i]);
collectManualStats(cePath, &stats);
-
auto dePath = create_data_user_de_package_path(uuid_, userId, pkgname);
collectManualStats(dePath, &stats);
+ ATRACE_END();
+ ATRACE_BEGIN("profiles");
auto userProfilePath = create_data_user_profile_package_path(userId, pkgname);
calculate_tree_size(userProfilePath, &stats.dataSize);
-
auto refProfilePath = create_data_ref_profile_package_path(pkgname);
calculate_tree_size(refProfilePath, &stats.codeSize);
+ ATRACE_END();
-#if MEASURE_EXTERNAL
+ ATRACE_BEGIN("external");
auto extPath = create_data_media_package_path(uuid_, userId, pkgname, "data");
collectManualStats(extPath, &extStats);
-
auto mediaPath = create_data_media_package_path(uuid_, userId, pkgname, "media");
calculate_tree_size(mediaPath, &extStats.dataSize);
-#endif
+ ATRACE_END();
}
+ ATRACE_BEGIN("dalvik");
int32_t sharedGid = multiuser_get_shared_gid(userId, appId);
if (sharedGid != -1) {
calculate_tree_size(create_data_dalvik_cache_path(), &stats.codeSize,
sharedGid, -1);
}
-
calculate_tree_size(create_data_misc_foreign_dex_path(userId), &stats.dataSize,
multiuser_get_uid(userId, appId), -1);
+ ATRACE_END();
}
std::vector<int64_t> ret;
@@ -1142,6 +1333,7 @@
std::vector<int64_t>* _aidl_return) {
ENFORCE_UID(AID_SYSTEM);
CHECK_ARGUMENT_UUID(uuid);
+ std::lock_guard<std::recursive_mutex> lock(mLock);
// When modifying this logic, always verify using tests:
// runtest -x frameworks/base/services/tests/servicestests/src/com/android/server/pm/InstallerTest.java -m testGetUserSize
@@ -1157,35 +1349,69 @@
const char* uuid_ = uuid ? uuid->c_str() : nullptr;
- auto obbPath = create_data_path(uuid_) + "/media/obb";
- calculate_tree_size(obbPath, &extStats.codeSize);
+ auto device = findQuotaDeviceForUuid(uuid);
+ if (device.empty()) {
+ flags &= ~FLAG_USE_QUOTA;
+ }
if (flags & FLAG_USE_QUOTA) {
- calculate_tree_size(create_data_app_path(uuid_), &stats.codeSize, -1, -1, true);
+ struct dqblk dq;
+ ATRACE_BEGIN("obb");
+ if (quotactl(QCMD(Q_GETQUOTA, GRPQUOTA), device.c_str(), AID_MEDIA_OBB,
+ reinterpret_cast<char*>(&dq)) != 0) {
+ if (errno != ESRCH) {
+ PLOG(ERROR) << "Failed to quotactl " << device << " for GID " << AID_MEDIA_OBB;
+ }
+ } else {
+#if MEASURE_DEBUG
+ LOG(DEBUG) << "quotactl() for GID " << AID_MEDIA_OBB << " " << dq.dqb_curspace;
+#endif
+ extStats.codeSize += dq.dqb_curspace;
+ }
+ ATRACE_END();
+
+ ATRACE_BEGIN("code");
+ calculate_tree_size(create_data_app_path(uuid_), &stats.codeSize, -1, -1, true);
+ ATRACE_END();
+
+ ATRACE_BEGIN("data");
auto cePath = create_data_user_ce_path(uuid_, userId);
collectManualStatsForUser(cePath, &stats, true);
-
auto dePath = create_data_user_de_path(uuid_, userId);
collectManualStatsForUser(dePath, &stats, true);
+ ATRACE_END();
+ ATRACE_BEGIN("profile");
auto userProfilePath = create_data_user_profile_path(userId);
calculate_tree_size(userProfilePath, &stats.dataSize, -1, -1, true);
-
auto refProfilePath = create_data_ref_profile_path();
calculate_tree_size(refProfilePath, &stats.codeSize, -1, -1, true);
+ ATRACE_END();
-#if MEASURE_EXTERNAL
- // TODO: measure external storage paths
+ ATRACE_BEGIN("external");
+ uid_t uid = multiuser_get_uid(userId, AID_MEDIA_RW);
+ if (quotactl(QCMD(Q_GETQUOTA, USRQUOTA), device.c_str(), uid,
+ reinterpret_cast<char*>(&dq)) != 0) {
+ if (errno != ESRCH) {
+ PLOG(ERROR) << "Failed to quotactl " << device << " for UID " << uid;
+ }
+ } else {
+#if MEASURE_DEBUG
+ LOG(DEBUG) << "quotactl() for UID " << uid << " " << dq.dqb_curspace;
#endif
+ extStats.dataSize += dq.dqb_curspace;
+ }
+ ATRACE_END();
+ ATRACE_BEGIN("dalvik");
calculate_tree_size(create_data_dalvik_cache_path(), &stats.codeSize,
-1, -1, true);
-
calculate_tree_size(create_data_misc_foreign_dex_path(userId), &stats.dataSize,
-1, -1, true);
+ ATRACE_END();
- auto device = findDeviceForUuid(uuid);
+ ATRACE_BEGIN("quota");
for (auto appId : appIds) {
if (appId >= AID_APP_START) {
collectQuotaStats(device, userId, appId, &stats, &extStats);
@@ -1195,28 +1421,44 @@
#endif
}
}
+ ATRACE_END();
} else {
- calculate_tree_size(create_data_app_path(uuid_), &stats.codeSize);
+ ATRACE_BEGIN("obb");
+ auto obbPath = create_data_path(uuid_) + "/media/obb";
+ calculate_tree_size(obbPath, &extStats.codeSize);
+ ATRACE_END();
+ ATRACE_BEGIN("code");
+ calculate_tree_size(create_data_app_path(uuid_), &stats.codeSize);
+ ATRACE_END();
+
+ ATRACE_BEGIN("data");
auto cePath = create_data_user_ce_path(uuid_, userId);
collectManualStatsForUser(cePath, &stats);
-
auto dePath = create_data_user_de_path(uuid_, userId);
collectManualStatsForUser(dePath, &stats);
+ ATRACE_END();
+ ATRACE_BEGIN("profile");
auto userProfilePath = create_data_user_profile_path(userId);
calculate_tree_size(userProfilePath, &stats.dataSize);
-
auto refProfilePath = create_data_ref_profile_path();
calculate_tree_size(refProfilePath, &stats.codeSize);
+ ATRACE_END();
-#if MEASURE_EXTERNAL
- // TODO: measure external storage paths
+ ATRACE_BEGIN("external");
+ auto dataMediaPath = create_data_media_path(uuid_, userId);
+ collectManualExternalStatsForUser(dataMediaPath, &extStats);
+#if MEASURE_DEBUG
+ LOG(DEBUG) << "Measured external data " << extStats.dataSize << " cache "
+ << extStats.cacheSize;
#endif
+ ATRACE_END();
+ ATRACE_BEGIN("dalvik");
calculate_tree_size(create_data_dalvik_cache_path(), &stats.codeSize);
-
calculate_tree_size(create_data_misc_foreign_dex_path(userId), &stats.dataSize);
+ ATRACE_END();
}
std::vector<int64_t> ret;
@@ -1237,6 +1479,7 @@
int32_t userId, int32_t flags, std::vector<int64_t>* _aidl_return) {
ENFORCE_UID(AID_SYSTEM);
CHECK_ARGUMENT_UUID(uuid);
+ std::lock_guard<std::recursive_mutex> lock(mLock);
// When modifying this logic, always verify using tests:
// runtest -x frameworks/base/services/tests/servicestests/src/com/android/server/pm/InstallerTest.java -m testGetExternalSize
@@ -1252,11 +1495,14 @@
int64_t videoSize = 0;
int64_t imageSize = 0;
+ auto device = findQuotaDeviceForUuid(uuid);
+ if (device.empty()) {
+ flags &= ~FLAG_USE_QUOTA;
+ }
+
if (flags & FLAG_USE_QUOTA) {
struct dqblk dq;
- auto device = findDeviceForUuid(uuid);
-
uid_t uid = multiuser_get_uid(userId, AID_MEDIA_RW);
if (quotactl(QCMD(Q_GETQUOTA, USRQUOTA), device.c_str(), uid,
reinterpret_cast<char*>(&dq)) != 0) {
@@ -1342,12 +1588,25 @@
return ok();
}
+binder::Status InstalldNativeService::setAppQuota(const std::unique_ptr<std::string>& uuid,
+ int32_t userId, int32_t appId, int64_t cacheQuota) {
+ ENFORCE_UID(AID_SYSTEM);
+ CHECK_ARGUMENT_UUID(uuid);
+ std::lock_guard<std::recursive_mutex> lock(mLock);
+
+ int32_t uid = multiuser_get_uid(userId, appId);
+ mCacheQuotas[uid] = cacheQuota;
+
+ return ok();
+}
+
// Dumps the contents of a profile file, using pkgname's dex files for pretty
// printing the result.
binder::Status InstalldNativeService::dumpProfiles(int32_t uid, const std::string& packageName,
const std::string& codePaths, bool* _aidl_return) {
ENFORCE_UID(AID_SYSTEM);
CHECK_ARGUMENT_PACKAGE_NAME(packageName);
+ std::lock_guard<std::recursive_mutex> lock(mLock);
const char* pkgname = packageName.c_str();
const char* code_paths = codePaths.c_str();
@@ -1361,6 +1620,7 @@
bool* _aidl_return) {
ENFORCE_UID(AID_SYSTEM);
CHECK_ARGUMENT_PACKAGE_NAME(packageName);
+ std::lock_guard<std::recursive_mutex> lock(mLock);
const char* pkgname = packageName.c_str();
*_aidl_return = analyse_profiles(uid, pkgname);
@@ -1377,6 +1637,7 @@
if (packageName && *packageName != "*") {
CHECK_ARGUMENT_PACKAGE_NAME(*packageName);
}
+ std::lock_guard<std::recursive_mutex> lock(mLock);
const char* apk_path = apkPath.c_str();
const char* pkgname = packageName ? packageName->c_str() : "*";
@@ -1393,6 +1654,8 @@
binder::Status InstalldNativeService::markBootComplete(const std::string& instructionSet) {
ENFORCE_UID(AID_SYSTEM);
+ std::lock_guard<std::recursive_mutex> lock(mLock);
+
const char* instruction_set = instructionSet.c_str();
char boot_marker_path[PKG_PATH_MAX];
@@ -1436,6 +1699,7 @@
ENFORCE_UID(AID_SYSTEM);
CHECK_ARGUMENT_UUID(uuid);
CHECK_ARGUMENT_PACKAGE_NAME(packageName);
+ std::lock_guard<std::recursive_mutex> lock(mLock);
const char* uuid_ = uuid ? uuid->c_str() : nullptr;
const char* pkgname = packageName.c_str();
@@ -1558,6 +1822,8 @@
binder::Status InstalldNativeService::idmap(const std::string& targetApkPath,
const std::string& overlayApkPath, int32_t uid) {
ENFORCE_UID(AID_SYSTEM);
+ std::lock_guard<std::recursive_mutex> lock(mLock);
+
const char* target_apk = targetApkPath.c_str();
const char* overlay_apk = overlayApkPath.c_str();
ALOGV("idmap target_apk=%s overlay_apk=%s uid=%d\n", target_apk, overlay_apk, uid);
@@ -1629,6 +1895,7 @@
ENFORCE_UID(AID_SYSTEM);
CHECK_ARGUMENT_UUID(uuid);
CHECK_ARGUMENT_PACKAGE_NAME(packageName);
+ std::lock_guard<std::recursive_mutex> lock(mLock);
binder::Status res = ok();
@@ -1657,6 +1924,8 @@
binder::Status InstalldNativeService::createOatDir(const std::string& oatDir,
const std::string& instructionSet) {
ENFORCE_UID(AID_SYSTEM);
+ std::lock_guard<std::recursive_mutex> lock(mLock);
+
const char* oat_dir = oatDir.c_str();
const char* instruction_set = instructionSet.c_str();
char oat_instr_dir[PKG_PATH_MAX];
@@ -1679,6 +1948,8 @@
binder::Status InstalldNativeService::rmPackageDir(const std::string& packageDir) {
ENFORCE_UID(AID_SYSTEM);
+ std::lock_guard<std::recursive_mutex> lock(mLock);
+
if (validate_apk_path(packageDir.c_str())) {
return error("Invalid path " + packageDir);
}
@@ -1691,6 +1962,8 @@
binder::Status InstalldNativeService::linkFile(const std::string& relativePath,
const std::string& fromBase, const std::string& toBase) {
ENFORCE_UID(AID_SYSTEM);
+ std::lock_guard<std::recursive_mutex> lock(mLock);
+
const char* relative_path = relativePath.c_str();
const char* from_base = fromBase.c_str();
const char* to_base = toBase.c_str();
@@ -1717,6 +1990,7 @@
binder::Status InstalldNativeService::moveAb(const std::string& apkPath,
const std::string& instructionSet, const std::string& outputPath) {
ENFORCE_UID(AID_SYSTEM);
+ std::lock_guard<std::recursive_mutex> lock(mLock);
const char* apk_path = apkPath.c_str();
const char* instruction_set = instructionSet.c_str();
@@ -1729,6 +2003,7 @@
binder::Status InstalldNativeService::deleteOdex(const std::string& apkPath,
const std::string& instructionSet, const std::string& outputPath) {
ENFORCE_UID(AID_SYSTEM);
+ std::lock_guard<std::recursive_mutex> lock(mLock);
const char* apk_path = apkPath.c_str();
const char* instruction_set = instructionSet.c_str();
@@ -1738,5 +2013,42 @@
return res ? ok() : error();
}
+binder::Status InstalldNativeService::invalidateMounts() {
+ ENFORCE_UID(AID_SYSTEM);
+ std::lock_guard<std::recursive_mutex> lock(mLock);
+
+ mQuotaDevices.clear();
+
+ std::ifstream in("/proc/mounts");
+ if (!in.is_open()) {
+ return error("Failed to read mounts");
+ }
+
+ std::string source;
+ std::string target;
+ std::string ignored;
+ struct dqblk dq;
+ while (!in.eof()) {
+ std::getline(in, source, ' ');
+ std::getline(in, target, ' ');
+ std::getline(in, ignored);
+
+ if (source.compare(0, 11, "/dev/block/") == 0) {
+ if (quotactl(QCMD(Q_GETQUOTA, USRQUOTA), source.c_str(), 0,
+ reinterpret_cast<char*>(&dq)) == 0) {
+ LOG(DEBUG) << "Found " << source << " with quota";
+ mQuotaDevices[target] = source;
+ }
+ }
+ }
+ return ok();
+}
+
+std::string InstalldNativeService::findQuotaDeviceForUuid(
+ const std::unique_ptr<std::string>& uuid) {
+ auto path = create_data_path(uuid ? uuid->c_str() : nullptr);
+ return mQuotaDevices[path];
+}
+
} // namespace installd
} // namespace android
diff --git a/cmds/installd/InstalldNativeService.h b/cmds/installd/InstalldNativeService.h
index 5397a74..0a9f12f 100644
--- a/cmds/installd/InstalldNativeService.h
+++ b/cmds/installd/InstalldNativeService.h
@@ -22,7 +22,9 @@
#include <unistd.h>
#include <vector>
+#include <unordered_map>
+#include <android-base/macros.h>
#include <binder/BinderService.h>
#include <cutils/multiuser.h>
@@ -66,6 +68,9 @@
binder::Status getExternalSize(const std::unique_ptr<std::string>& uuid,
int32_t userId, int32_t flags, std::vector<int64_t>* _aidl_return);
+ binder::Status setAppQuota(const std::unique_ptr<std::string>& uuid,
+ int32_t userId, int32_t appId, int64_t cacheQuota);
+
binder::Status moveCompleteApp(const std::unique_ptr<std::string>& fromUuid,
const std::unique_ptr<std::string>& toUuid, const std::string& packageName,
const std::string& dataAppName, int32_t appId, const std::string& seInfo,
@@ -89,7 +94,8 @@
int32_t uid);
binder::Status rmPackageDir(const std::string& packageDir);
binder::Status markBootComplete(const std::string& instructionSet);
- binder::Status freeCache(const std::unique_ptr<std::string>& uuid, int64_t freeStorageSize);
+ binder::Status freeCache(const std::unique_ptr<std::string>& uuid, int64_t freeStorageSize,
+ int32_t flags);
binder::Status linkNativeLibraryDirectory(const std::unique_ptr<std::string>& uuid,
const std::string& packageName, const std::string& nativeLibPath32, int32_t userId);
binder::Status createOatDir(const std::string& oatDir, const std::string& instructionSet);
@@ -99,6 +105,18 @@
const std::string& outputPath);
binder::Status deleteOdex(const std::string& apkPath, const std::string& instructionSet,
const std::string& outputPath);
+
+ binder::Status invalidateMounts();
+
+private:
+ std::recursive_mutex mLock;
+
+ /* Map from mount point to underlying device node */
+ std::unordered_map<std::string, std::string> mQuotaDevices;
+ /* Map from UID to cache quota size */
+ std::unordered_map<uid_t, int64_t> mCacheQuotas;
+
+ std::string findQuotaDeviceForUuid(const std::unique_ptr<std::string>& uuid);
};
} // namespace installd
diff --git a/cmds/installd/binder/android/os/IInstalld.aidl b/cmds/installd/binder/android/os/IInstalld.aidl
index 6e4d7fa..aa5e4f2 100644
--- a/cmds/installd/binder/android/os/IInstalld.aidl
+++ b/cmds/installd/binder/android/os/IInstalld.aidl
@@ -38,6 +38,8 @@
long[] getUserSize(@nullable @utf8InCpp String uuid, int userId, int flags, in int[] appIds);
long[] getExternalSize(@nullable @utf8InCpp String uuid, int userId, int flags);
+ void setAppQuota(@nullable @utf8InCpp String uuid, int userId, int appId, long cacheQuota);
+
void moveCompleteApp(@nullable @utf8InCpp String fromUuid, @nullable @utf8InCpp String toUuid,
@utf8InCpp String packageName, @utf8InCpp String dataAppName, int appId,
@utf8InCpp String seInfo, int targetSdkVersion);
@@ -58,7 +60,7 @@
void idmap(@utf8InCpp String targetApkPath, @utf8InCpp String overlayApkPath, int uid);
void rmPackageDir(@utf8InCpp String packageDir);
void markBootComplete(@utf8InCpp String instructionSet);
- void freeCache(@nullable @utf8InCpp String uuid, long freeStorageSize);
+ void freeCache(@nullable @utf8InCpp String uuid, long freeStorageSize, int flags);
void linkNativeLibraryDirectory(@nullable @utf8InCpp String uuid,
@utf8InCpp String packageName, @utf8InCpp String nativeLibPath32, int userId);
void createOatDir(@utf8InCpp String oatDir, @utf8InCpp String instructionSet);
@@ -68,4 +70,6 @@
@utf8InCpp String outputPath);
void deleteOdex(@utf8InCpp String apkPath, @utf8InCpp String instructionSet,
@utf8InCpp String outputPath);
+
+ void invalidateMounts();
}
diff --git a/cmds/installd/dexopt.cpp b/cmds/installd/dexopt.cpp
index 76d5695..1565d0d 100644
--- a/cmds/installd/dexopt.cpp
+++ b/cmds/installd/dexopt.cpp
@@ -904,7 +904,7 @@
//
// Usage example:
//
-// Dex2oatFileWrapper<std::function<void ()>> file(open(...),
+// Dex2oatFileWrapper file(open(...),
// [name]() {
// unlink(name.c_str());
// });
@@ -927,14 +927,30 @@
// // At this point, when the Dex2oatFileWrapper is destructed, the cleanup function will not run
// // (leaving the file around; after the fd is closed).
//
-template <typename Cleanup>
class Dex2oatFileWrapper {
public:
- Dex2oatFileWrapper() : value_(-1), cleanup_(), do_cleanup_(true) {
+ Dex2oatFileWrapper() : value_(-1), cleanup_(), do_cleanup_(true), auto_close_(true) {
}
- Dex2oatFileWrapper(int value, Cleanup cleanup)
- : value_(value), cleanup_(cleanup), do_cleanup_(true) {}
+ Dex2oatFileWrapper(int value, std::function<void ()> cleanup)
+ : value_(value), cleanup_(cleanup), do_cleanup_(true), auto_close_(true) {}
+
+ Dex2oatFileWrapper(Dex2oatFileWrapper&& other) {
+ value_ = other.value_;
+ cleanup_ = other.cleanup_;
+ do_cleanup_ = other.do_cleanup_;
+ auto_close_ = other.auto_close_;
+ other.release();
+ }
+
+ Dex2oatFileWrapper& operator=(Dex2oatFileWrapper&& other) {
+ value_ = other.value_;
+ cleanup_ = other.cleanup_;
+ do_cleanup_ = other.do_cleanup_;
+ auto_close_ = other.auto_close_;
+ other.release();
+ return *this;
+ }
~Dex2oatFileWrapper() {
reset(-1);
@@ -949,7 +965,7 @@
}
void reset(int new_value) {
- if (value_ >= 0) {
+ if (auto_close_ && value_ >= 0) {
close(value_);
}
if (do_cleanup_ && cleanup_ != nullptr) {
@@ -959,8 +975,8 @@
value_ = new_value;
}
- void reset(int new_value, Cleanup new_cleanup) {
- if (value_ >= 0) {
+ void reset(int new_value, std::function<void ()> new_cleanup) {
+ if (auto_close_ && value_ >= 0) {
close(value_);
}
if (do_cleanup_ && cleanup_ != nullptr) {
@@ -971,77 +987,125 @@
cleanup_ = new_cleanup;
}
+ void DisableAutoClose() {
+ auto_close_ = false;
+ }
+
private:
+ void release() {
+ value_ = -1;
+ do_cleanup_ = false;
+ cleanup_ = nullptr;
+ }
int value_;
- Cleanup cleanup_;
+ std::function<void ()> cleanup_;
bool do_cleanup_;
+ bool auto_close_;
};
-int dexopt(const char* apk_path, uid_t uid, const char* pkgname, const char* instruction_set,
- int dexopt_needed, const char* oat_dir, int dexopt_flags,const char* compiler_filter,
- const char* volume_uuid ATTRIBUTE_UNUSED, const char* shared_libraries) {
- bool is_public = ((dexopt_flags & DEXOPT_PUBLIC) != 0);
- bool vm_safe_mode = (dexopt_flags & DEXOPT_SAFEMODE) != 0;
- bool debuggable = (dexopt_flags & DEXOPT_DEBUGGABLE) != 0;
- bool boot_complete = (dexopt_flags & DEXOPT_BOOTCOMPLETE) != 0;
- bool profile_guided = (dexopt_flags & DEXOPT_PROFILE_GUIDED) != 0;
+// (re)Creates the app image if needed.
+Dex2oatFileWrapper maybe_open_app_image(const char* out_oat_path, bool profile_guided,
+ bool is_public, int uid) {
+ // Use app images only if it is enabled (by a set image format) and we are compiling
+ // profile-guided (so the app image doesn't conservatively contain all classes).
+ if (!profile_guided) {
+ return Dex2oatFileWrapper();
+ }
- CHECK(pkgname != nullptr);
- CHECK(pkgname[0] != 0);
+ const std::string image_path = create_image_filename(out_oat_path);
+ if (image_path.empty()) {
+ // Happens when the out_oat_path has an unknown extension.
+ return Dex2oatFileWrapper();
+ }
+ char app_image_format[kPropertyValueMax];
+ bool have_app_image_format =
+ get_property("dalvik.vm.appimageformat", app_image_format, NULL) > 0;
+ if (!have_app_image_format) {
+ return Dex2oatFileWrapper();
+ }
+ // Recreate is true since we do not want to modify a mapped image. If the app is
+ // already running and we modify the image file, it can cause crashes (b/27493510).
+ Dex2oatFileWrapper wrapper_fd(
+ open_output_file(image_path.c_str(), true /*recreate*/, 0600 /*permissions*/),
+ [image_path]() { unlink(image_path.c_str()); });
+ if (wrapper_fd.get() < 0) {
+ // Could not create application image file. Go on since we can compile without it.
+ LOG(ERROR) << "installd could not create '" << image_path
+ << "' for image file during dexopt";
+ // If we have a valid image file path but no image fd, explicitly erase the image file.
+ if (unlink(image_path.c_str()) < 0) {
+ if (errno != ENOENT) {
+ PLOG(ERROR) << "Couldn't unlink image file " << image_path;
+ }
+ }
+ } else if (!set_permissions_and_ownership(
+ wrapper_fd.get(), is_public, uid, image_path.c_str())) {
+ ALOGE("installd cannot set owner '%s' for image during dexopt\n", image_path.c_str());
+ wrapper_fd.reset(-1);
+ }
+ return wrapper_fd;
+}
+
+// Creates the dexopt swap file if necessary and return its fd.
+// Returns -1 if there's no need for a swap or in case of errors.
+base::unique_fd maybe_open_dexopt_swap_file(const char* out_oat_path) {
+ if (!ShouldUseSwapFileForDexopt()) {
+ return base::unique_fd();
+ }
+ // Make sure there really is enough space.
+ char swap_file_name[PKG_PATH_MAX];
+ strcpy(swap_file_name, out_oat_path);
+ if (!add_extension_to_file_name(swap_file_name, ".swap")) {
+ return base::unique_fd();
+ }
+ base::unique_fd swap_fd(open_output_file(
+ swap_file_name, /*recreate*/true, /*permissions*/0600));
+ if (swap_fd.get() < 0) {
+ // Could not create swap file. Optimistically go on and hope that we can compile
+ // without it.
+ ALOGE("installd could not create '%s' for swap during dexopt\n", swap_file_name);
+ } else {
+ // Immediately unlink. We don't really want to hit flash.
+ if (unlink(swap_file_name) < 0) {
+ PLOG(ERROR) << "Couldn't unlink swap file " << swap_file_name;
+ }
+ }
+ return swap_fd;
+}
+
+// Opens the reference profiles if needed.
+// Note that the reference profile might not exist so it's OK if the fd will be -1.
+Dex2oatFileWrapper maybe_open_reference_profile(const char* pkgname, bool profile_guided,
+ bool is_public, int uid) {
// Public apps should not be compiled with profile information ever. Same goes for the special
// package '*' used for the system server.
- Dex2oatFileWrapper<std::function<void ()>> reference_profile_fd;
- if (!is_public && pkgname[0] != '*') {
+ if (profile_guided && !is_public && (pkgname[0] != '*')) {
// Open reference profile in read only mode as dex2oat does not get write permissions.
const std::string pkgname_str(pkgname);
- reference_profile_fd.reset(open_reference_profile(uid, pkgname, /*read_write*/ false),
- [pkgname_str]() {
- clear_reference_profile(pkgname_str.c_str());
- });
- // Note: it's OK to not find a profile here.
+ return Dex2oatFileWrapper(
+ open_reference_profile(uid, pkgname, /*read_write*/ false),
+ [pkgname_str]() {
+ clear_reference_profile(pkgname_str.c_str());
+ });
+ } else {
+ return Dex2oatFileWrapper();
}
+}
- if ((dexopt_flags & ~DEXOPT_MASK) != 0) {
- LOG_FATAL("dexopt flags contains unknown fields\n");
- }
-
- char out_oat_path[PKG_PATH_MAX];
- if (!create_oat_out_path(apk_path, instruction_set, oat_dir, out_oat_path)) {
- return false;
- }
-
- const char *input_file = apk_path;
- struct stat input_stat;
- memset(&input_stat, 0, sizeof(input_stat));
- stat(input_file, &input_stat);
-
- // Open the input file.
- base::unique_fd input_fd(open(input_file, O_RDONLY, 0));
- if (input_fd.get() < 0) {
- ALOGE("installd cannot open '%s' for input during dexopt\n", input_file);
- return -1;
- }
-
- // Create the output OAT file.
- const std::string out_oat_path_str(out_oat_path);
- Dex2oatFileWrapper<std::function<void ()>> out_oat_fd(
- open_output_file(out_oat_path, /*recreate*/true, /*permissions*/0644),
- [out_oat_path_str]() { unlink(out_oat_path_str.c_str()); });
- if (out_oat_fd.get() < 0) {
- ALOGE("installd cannot open '%s' for output during dexopt\n", out_oat_path);
- return -1;
- }
- if (!set_permissions_and_ownership(out_oat_fd.get(), is_public, uid, out_oat_path)) {
- return -1;
- }
-
+// Opens the vdex files and assigns the input fd to in_vdex_wrapper_fd and the output fd to
+// out_vdex_wrapper_fd. Returns true for success or false in case of errors.
+bool open_vdex_files(const char* apk_path, const char* out_oat_path, int dexopt_needed,
+ const char* instruction_set, bool is_public, int uid,
+ Dex2oatFileWrapper* in_vdex_wrapper_fd,
+ Dex2oatFileWrapper* out_vdex_wrapper_fd) {
+ CHECK(in_vdex_wrapper_fd != nullptr);
+ CHECK(out_vdex_wrapper_fd != nullptr);
// Open the existing VDEX. We do this before creating the new output VDEX, which will
// unlink the old one.
char in_odex_path[PKG_PATH_MAX];
int dexopt_action = abs(dexopt_needed);
bool is_odex_location = dexopt_needed < 0;
- base::unique_fd in_vdex_fd;
std::string in_vdex_path_str;
if (dexopt_action != DEX2OAT_FROM_SCRATCH) {
// Open the possibly existing vdex. If none exist, we pass -1 to dex2oat for input-vdex-fd.
@@ -1051,7 +1115,7 @@
path = in_odex_path;
} else {
ALOGE("installd cannot compute input vdex location for '%s'\n", apk_path);
- return -1;
+ return false;
}
} else {
path = out_oat_path;
@@ -1059,108 +1123,138 @@
in_vdex_path_str = create_vdex_filename(path);
if (in_vdex_path_str.empty()) {
ALOGE("installd cannot compute input vdex location for '%s'\n", path);
- return -1;
+ return false;
}
if (dexopt_action == DEX2OAT_FOR_BOOT_IMAGE) {
// When we dex2oat because iof boot image change, we are going to update
// in-place the vdex file.
- in_vdex_fd.reset(open(in_vdex_path_str.c_str(), O_RDWR, 0));
+ in_vdex_wrapper_fd->reset(open(in_vdex_path_str.c_str(), O_RDWR, 0));
} else {
- in_vdex_fd.reset(open(in_vdex_path_str.c_str(), O_RDONLY, 0));
+ in_vdex_wrapper_fd->reset(open(in_vdex_path_str.c_str(), O_RDONLY, 0));
}
}
// Infer the name of the output VDEX and create it.
- const std::string out_vdex_path_str = create_vdex_filename(out_oat_path_str);
+ const std::string out_vdex_path_str = create_vdex_filename(out_oat_path);
if (out_vdex_path_str.empty()) {
- return -1;
+ return false;
}
- Dex2oatFileWrapper<std::function<void ()>> out_vdex_wrapper_fd;
- int out_vdex_fd = -1;
// If we are compiling because the boot image is out of date, we do not
// need to recreate a vdex, and can use the same existing one.
if (dexopt_action == DEX2OAT_FOR_BOOT_IMAGE &&
- in_vdex_fd != -1 &&
+ in_vdex_wrapper_fd->get() != -1 &&
in_vdex_path_str == out_vdex_path_str) {
- out_vdex_fd = in_vdex_fd;
+ out_vdex_wrapper_fd->reset(in_vdex_wrapper_fd->get());
+ // Disable auto close for the in wrapper fd (it will be done when destructing the out
+ // wrapper).
+ in_vdex_wrapper_fd->DisableAutoClose();
} else {
- out_vdex_wrapper_fd.reset(
+ out_vdex_wrapper_fd->reset(
open_output_file(out_vdex_path_str.c_str(), /*recreate*/true, /*permissions*/0644),
[out_vdex_path_str]() { unlink(out_vdex_path_str.c_str()); });
- out_vdex_fd = out_vdex_wrapper_fd.get();
- if (out_vdex_fd < 0) {
- ALOGE("installd cannot open '%s' for output during dexopt\n", out_vdex_path_str.c_str());
- return -1;
+ if (out_vdex_wrapper_fd->get() < 0) {
+ ALOGE("installd cannot open vdex'%s' during dexopt\n", out_vdex_path_str.c_str());
+ return false;
}
}
- if (!set_permissions_and_ownership(out_vdex_fd, is_public,
- uid, out_vdex_path_str.c_str())) {
+ if (!set_permissions_and_ownership(out_vdex_wrapper_fd->get(), is_public, uid,
+ out_vdex_path_str.c_str())) {
+ ALOGE("installd cannot set owner '%s' for vdex during dexopt\n", out_vdex_path_str.c_str());
+ return false;
+ }
+
+ // If we got here we successfully opened the vdex files.
+ return true;
+}
+
+// Opens the output oat file for the given apk.
+// If successful it stores the output path into out_oat_path and returns true.
+Dex2oatFileWrapper open_oat_out_file(const char* apk_path, const char* oat_dir,
+ bool is_public, int uid, const char* instruction_set, char* out_oat_path) {
+ if (!create_oat_out_path(apk_path, instruction_set, oat_dir, out_oat_path)) {
+ return Dex2oatFileWrapper();
+ }
+ const std::string out_oat_path_str(out_oat_path);
+ Dex2oatFileWrapper wrapper_fd(
+ open_output_file(out_oat_path, /*recreate*/true, /*permissions*/0644),
+ [out_oat_path_str]() { unlink(out_oat_path_str.c_str()); });
+ if (wrapper_fd.get() < 0) {
+ ALOGE("installd cannot open '%s' for output during dexopt\n", out_oat_path);
+ } else if (!set_permissions_and_ownership(wrapper_fd.get(), is_public, uid, out_oat_path)) {
+ ALOGE("installd cannot set owner '%s' for output during dexopt\n", out_oat_path);
+ wrapper_fd.reset(-1);
+ }
+ return wrapper_fd;
+}
+
+// Updates the access times of out_oat_path based on those from apk_path.
+void update_out_oat_access_times(const char* apk_path, const char* out_oat_path) {
+ struct stat input_stat;
+ memset(&input_stat, 0, sizeof(input_stat));
+ if (stat(apk_path, &input_stat) != 0) {
+ PLOG(ERROR) << "Could not stat " << apk_path << " during dexopt";
+ return;
+ }
+
+ struct utimbuf ut;
+ ut.actime = input_stat.st_atime;
+ ut.modtime = input_stat.st_mtime;
+ if (utime(out_oat_path, &ut) != 0) {
+ PLOG(WARNING) << "Could not update access times for " << apk_path << " during dexopt";
+ }
+}
+
+int dexopt(const char* apk_path, uid_t uid, const char* pkgname, const char* instruction_set,
+ int dexopt_needed, const char* oat_dir, int dexopt_flags,const char* compiler_filter,
+ const char* volume_uuid ATTRIBUTE_UNUSED, const char* shared_libraries) {
+ CHECK(pkgname != nullptr);
+ CHECK(pkgname[0] != 0);
+ if ((dexopt_flags & ~DEXOPT_MASK) != 0) {
+ LOG_FATAL("dexopt flags contains unknown fields\n");
+ }
+
+ bool is_public = ((dexopt_flags & DEXOPT_PUBLIC) != 0);
+ bool vm_safe_mode = (dexopt_flags & DEXOPT_SAFEMODE) != 0;
+ bool debuggable = (dexopt_flags & DEXOPT_DEBUGGABLE) != 0;
+ bool boot_complete = (dexopt_flags & DEXOPT_BOOTCOMPLETE) != 0;
+ bool profile_guided = (dexopt_flags & DEXOPT_PROFILE_GUIDED) != 0;
+
+ // Open the input file.
+ base::unique_fd input_fd(open(apk_path, O_RDONLY, 0));
+ if (input_fd.get() < 0) {
+ ALOGE("installd cannot open '%s' for input during dexopt\n", apk_path);
+ return -1;
+ }
+
+ // Create the output OAT file.
+ char out_oat_path[PKG_PATH_MAX];
+ Dex2oatFileWrapper out_oat_fd = open_oat_out_file(apk_path, oat_dir, is_public, uid,
+ instruction_set, out_oat_path);
+ if (out_oat_fd.get() < 0) {
+ return -1;
+ }
+
+ // Open vdex files.
+ Dex2oatFileWrapper in_vdex_fd;
+ Dex2oatFileWrapper out_vdex_fd;
+ if (!open_vdex_files(apk_path, out_oat_path, dexopt_needed, instruction_set, is_public, uid,
+ &in_vdex_fd, &out_vdex_fd)) {
return -1;
}
// Create a swap file if necessary.
- base::unique_fd swap_fd;
- if (ShouldUseSwapFileForDexopt()) {
- // Make sure there really is enough space.
- char swap_file_name[PKG_PATH_MAX];
- strcpy(swap_file_name, out_oat_path);
- if (add_extension_to_file_name(swap_file_name, ".swap")) {
- swap_fd.reset(open_output_file(swap_file_name, /*recreate*/true, /*permissions*/0600));
- }
- if (swap_fd.get() < 0) {
- // Could not create swap file. Optimistically go on and hope that we can compile
- // without it.
- ALOGE("installd could not create '%s' for swap during dexopt\n", swap_file_name);
- } else {
- // Immediately unlink. We don't really want to hit flash.
- if (unlink(swap_file_name) < 0) {
- PLOG(ERROR) << "Couldn't unlink swap file " << swap_file_name;
- }
- }
- }
+ base::unique_fd swap_fd = maybe_open_dexopt_swap_file(out_oat_path);
- // Avoid generating an app image for extract only since it will not contain any classes.
- Dex2oatFileWrapper<std::function<void ()>> image_fd;
- const std::string image_path = create_image_filename(out_oat_path);
- if (!image_path.empty()) {
- char app_image_format[kPropertyValueMax];
- bool have_app_image_format =
- get_property("dalvik.vm.appimageformat", app_image_format, NULL) > 0;
- // Use app images only if it is enabled (by a set image format) and we are compiling
- // profile-guided (so the app image doesn't conservatively contain all classes).
- if (profile_guided && have_app_image_format) {
- // Recreate is true since we do not want to modify a mapped image. If the app is
- // already running and we modify the image file, it can cause crashes (b/27493510).
- image_fd.reset(open_output_file(image_path.c_str(),
- true /*recreate*/,
- 0600 /*permissions*/),
- [image_path]() { unlink(image_path.c_str()); }
- );
- if (image_fd.get() < 0) {
- // Could not create application image file. Go on since we can compile without
- // it.
- LOG(ERROR) << "installd could not create '"
- << image_path
- << "' for image file during dexopt";
- } else if (!set_permissions_and_ownership(image_fd.get(),
- is_public,
- uid,
- image_path.c_str())) {
- image_fd.reset(-1);
- }
- }
- // If we have a valid image file path but no image fd, explicitly erase the image file.
- if (image_fd.get() < 0) {
- if (unlink(image_path.c_str()) < 0) {
- if (errno != ENOENT) {
- PLOG(ERROR) << "Couldn't unlink image file " << image_path;
- }
- }
- }
- }
+ // Create the app image file if needed.
+ Dex2oatFileWrapper image_fd =
+ maybe_open_app_image(out_oat_path, profile_guided, is_public, uid);
- ALOGV("DexInv: --- BEGIN '%s' ---\n", input_file);
+ // Open the reference profile if needed.
+ Dex2oatFileWrapper reference_profile_fd =
+ maybe_open_reference_profile(pkgname, profile_guided, is_public, uid);
+
+ ALOGV("DexInv: --- BEGIN '%s' ---\n", apk_path);
pid_t pid = fork();
if (pid == 0) {
@@ -1174,11 +1268,11 @@
}
// Pass dex2oat the relative path to the input file.
- const char *input_file_name = get_location_from_path(input_file);
+ const char *input_file_name = get_location_from_path(apk_path);
run_dex2oat(input_fd.get(),
out_oat_fd.get(),
in_vdex_fd.get(),
- out_vdex_fd,
+ out_vdex_fd.get(),
image_fd.get(),
input_file_name,
out_oat_path,
@@ -1194,21 +1288,18 @@
} else {
int res = wait_child(pid);
if (res == 0) {
- ALOGV("DexInv: --- END '%s' (success) ---\n", input_file);
+ ALOGV("DexInv: --- END '%s' (success) ---\n", apk_path);
} else {
- ALOGE("DexInv: --- END '%s' --- status=0x%04x, process failed\n", input_file, res);
+ ALOGE("DexInv: --- END '%s' --- status=0x%04x, process failed\n", apk_path, res);
return -1;
}
}
- struct utimbuf ut;
- ut.actime = input_stat.st_atime;
- ut.modtime = input_stat.st_mtime;
- utime(out_oat_path, &ut);
+ update_out_oat_access_times(apk_path, out_oat_path);
// We've been successful, don't delete output.
out_oat_fd.SetCleanup(false);
- out_vdex_wrapper_fd.SetCleanup(false);
+ out_vdex_fd.SetCleanup(false);
image_fd.SetCleanup(false);
reference_profile_fd.SetCleanup(false);
diff --git a/cmds/installd/utils.h b/cmds/installd/utils.h
index f2f0cbb..5e396c7 100644
--- a/cmds/installd/utils.h
+++ b/cmds/installd/utils.h
@@ -31,7 +31,6 @@
#include <installd_constants.h>
#define MEASURE_DEBUG 0
-#define MEASURE_EXTERNAL 0
namespace android {
namespace installd {
diff --git a/cmds/servicemanager/service_manager.c b/cmds/servicemanager/service_manager.c
index a31e3c7..43c4c8b 100644
--- a/cmds/servicemanager/service_manager.c
+++ b/cmds/servicemanager/service_manager.c
@@ -363,6 +363,7 @@
int main()
{
struct binder_state *bs;
+ union selinux_callback cb;
bs = binder_open(128*1024);
if (!bs) {
@@ -375,6 +376,11 @@
return -1;
}
+ cb.func_audit = audit_callback;
+ selinux_set_callback(SELINUX_CB_AUDIT, cb);
+ cb.func_log = selinux_log_callback;
+ selinux_set_callback(SELINUX_CB_LOG, cb);
+
sehandle = selinux_android_service_context_handle();
selinux_status_open(true);
@@ -388,11 +394,6 @@
abort();
}
- union selinux_callback cb;
- cb.func_audit = audit_callback;
- selinux_set_callback(SELINUX_CB_AUDIT, cb);
- cb.func_log = selinux_log_callback;
- selinux_set_callback(SELINUX_CB_LOG, cb);
binder_loop(bs, svcmgr_handler);
diff --git a/libs/gui/Sensor.cpp b/libs/gui/Sensor.cpp
index 7510429..2c87562 100644
--- a/libs/gui/Sensor.cpp
+++ b/libs/gui/Sensor.cpp
@@ -219,7 +219,10 @@
break;
case SENSOR_TYPE_DYNAMIC_SENSOR_META:
mStringType = SENSOR_STRING_TYPE_DYNAMIC_SENSOR_META;
- mFlags = SENSOR_FLAG_SPECIAL_REPORTING_MODE; // special trigger and non-wake up
+ mFlags |= SENSOR_FLAG_SPECIAL_REPORTING_MODE; // special trigger
+ if (halVersion < SENSORS_DEVICE_API_VERSION_1_3) {
+ mFlags |= SENSOR_FLAG_WAKE_UP;
+ }
break;
case SENSOR_TYPE_POSE_6DOF:
mStringType = SENSOR_STRING_TYPE_POSE_6DOF;
diff --git a/opengl/libagl/egl.cpp b/opengl/libagl/egl.cpp
index 493c0b8..48bf676 100644
--- a/opengl/libagl/egl.cpp
+++ b/opengl/libagl/egl.cpp
@@ -740,6 +740,7 @@
case GGL_PIXEL_FORMAT_RGB_565: size *= 2; break;
case GGL_PIXEL_FORMAT_RGBA_8888: size *= 4; break;
case GGL_PIXEL_FORMAT_RGBX_8888: size *= 4; break;
+ case GGL_PIXEL_FORMAT_BGRA_8888: size *= 4; break;
default:
ALOGE("incompatible pixel format for pbuffer (format=%d)", f);
pbuffer.data = 0;
@@ -1027,6 +1028,19 @@
{ EGL_SURFACE_TYPE, EGL_WINDOW_BIT|EGL_PBUFFER_BIT|EGL_PIXMAP_BIT },
};
+// BGRA 8888 config
+static config_pair_t const config_8_attribute_list[] = {
+ { EGL_BUFFER_SIZE, 32 },
+ { EGL_ALPHA_SIZE, 8 },
+ { EGL_BLUE_SIZE, 8 },
+ { EGL_GREEN_SIZE, 8 },
+ { EGL_RED_SIZE, 8 },
+ { EGL_DEPTH_SIZE, 0 },
+ { EGL_CONFIG_ID, 8 },
+ { EGL_NATIVE_VISUAL_ID, GGL_PIXEL_FORMAT_BGRA_8888 },
+ { EGL_SURFACE_TYPE, EGL_WINDOW_BIT|EGL_PBUFFER_BIT|EGL_PIXMAP_BIT },
+};
+
static configs_t const gConfigs[] = {
{ config_0_attribute_list, NELEM(config_0_attribute_list) },
{ config_1_attribute_list, NELEM(config_1_attribute_list) },
@@ -1036,6 +1050,7 @@
{ config_5_attribute_list, NELEM(config_5_attribute_list) },
{ config_6_attribute_list, NELEM(config_6_attribute_list) },
{ config_7_attribute_list, NELEM(config_7_attribute_list) },
+ { config_8_attribute_list, NELEM(config_8_attribute_list) },
};
static config_management_t const gConfigManagement[] = {
@@ -1118,6 +1133,10 @@
pixelFormat = GGL_PIXEL_FORMAT_A_8;
depthFormat = GGL_PIXEL_FORMAT_Z_16;
break;
+ case 8:
+ pixelFormat = GGL_PIXEL_FORMAT_BGRA_8888;
+ depthFormat = 0;
+ break;
default:
return NAME_NOT_FOUND;
}