Loading core/java/android/content/res/ApkAssets.java +49 −7 Original line number Diff line number Diff line Loading @@ -25,6 +25,7 @@ import android.content.res.loader.ResourcesProvider; import android.ravenwood.annotation.RavenwoodClassLoadHook; import android.ravenwood.annotation.RavenwoodKeepWholeClass; import android.text.TextUtils; import android.util.Log; import com.android.internal.annotations.GuardedBy; Loading @@ -50,6 +51,7 @@ import java.util.Objects; @RavenwoodKeepWholeClass @RavenwoodClassLoadHook(RavenwoodClassLoadHook.LIBANDROID_LOADING_HOOK) public final class ApkAssets { private static final boolean DEBUG = false; /** * The apk assets contains framework resource values specified by the system. Loading Loading @@ -134,6 +136,17 @@ public final class ApkAssets { @Nullable private final AssetsProvider mAssets; @NonNull private String mName; private static final int UPTODATE_FALSE = 0; private static final int UPTODATE_TRUE = 1; private static final int UPTODATE_ALWAYS_TRUE = 2; // Start with the only value that may change later and would force a native call to // double check it. private int mPreviousUpToDateResult = UPTODATE_TRUE; /** * Creates a new ApkAssets instance from the given path on disk. * Loading Loading @@ -304,7 +317,7 @@ public final class ApkAssets { private ApkAssets(@FormatType int format, @NonNull String path, @PropertyFlags int flags, @Nullable AssetsProvider assets) throws IOException { this(format, flags, assets); this(format, flags, assets, path); Objects.requireNonNull(path, "path"); mNativePtr = nativeLoad(format, path, flags, assets); mStringBlock = new StringBlock(nativeGetStringBlock(mNativePtr), true /*useSparse*/); Loading @@ -313,7 +326,7 @@ public final class ApkAssets { private ApkAssets(@FormatType int format, @NonNull FileDescriptor fd, @NonNull String friendlyName, @PropertyFlags int flags, @Nullable AssetsProvider assets) throws IOException { this(format, flags, assets); this(format, flags, assets, friendlyName); Objects.requireNonNull(fd, "fd"); Objects.requireNonNull(friendlyName, "friendlyName"); mNativePtr = nativeLoadFd(format, fd, friendlyName, flags, assets); Loading @@ -323,7 +336,7 @@ public final class ApkAssets { private ApkAssets(@FormatType int format, @NonNull FileDescriptor fd, @NonNull String friendlyName, long offset, long length, @PropertyFlags int flags, @Nullable AssetsProvider assets) throws IOException { this(format, flags, assets); this(format, flags, assets, friendlyName); Objects.requireNonNull(fd, "fd"); Objects.requireNonNull(friendlyName, "friendlyName"); mNativePtr = nativeLoadFdOffsets(format, fd, friendlyName, offset, length, flags, assets); Loading @@ -331,16 +344,17 @@ public final class ApkAssets { } private ApkAssets(@PropertyFlags int flags, @Nullable AssetsProvider assets) { this(FORMAT_APK, flags, assets); this(FORMAT_APK, flags, assets, "empty"); mNativePtr = nativeLoadEmpty(flags, assets); mStringBlock = null; } private ApkAssets(@FormatType int format, @PropertyFlags int flags, @Nullable AssetsProvider assets) { @Nullable AssetsProvider assets, @NonNull String name) { mFlags = flags; mAssets = assets; mIsOverlay = format == FORMAT_IDMAP; if (DEBUG) mName = name; } @UnsupportedAppUsage Loading Loading @@ -421,13 +435,41 @@ public final class ApkAssets { } } private static double intervalMs(long beginNs, long endNs) { return (endNs - beginNs) / 1000000.0; } /** * Returns false if the underlying APK was changed since this ApkAssets was loaded. */ public boolean isUpToDate() { // This function is performance-critical - it's called multiple times on every Resources // object creation, and on few other cache accesses - so it's important to avoid the native // call when we know for sure what it will return (which is the case for both ALWAYS_TRUE // and FALSE). if (mPreviousUpToDateResult != UPTODATE_TRUE) { return mPreviousUpToDateResult == UPTODATE_ALWAYS_TRUE; } final long beforeTs, afterLockTs, afterNativeTs, afterUnlockTs; if (DEBUG) beforeTs = System.nanoTime(); final int res; synchronized (this) { return nativeIsUpToDate(mNativePtr); if (DEBUG) afterLockTs = System.nanoTime(); res = nativeIsUpToDate(mNativePtr); if (DEBUG) afterNativeTs = System.nanoTime(); } if (DEBUG) { afterUnlockTs = System.nanoTime(); if (afterUnlockTs - beforeTs >= 10L * 1000000) { Log.d("ApkAssets", "isUpToDate(" + mName + ") took " + intervalMs(beforeTs, afterUnlockTs) + " ms: " + intervalMs(beforeTs, afterLockTs) + " / " + intervalMs(afterLockTs, afterNativeTs) + " / " + intervalMs(afterNativeTs, afterUnlockTs)); } } mPreviousUpToDateResult = res; return res != UPTODATE_FALSE; } public boolean isSystem() { Loading Loading @@ -487,7 +529,7 @@ public final class ApkAssets { private static native @NonNull String nativeGetAssetPath(long ptr); private static native @NonNull String nativeGetDebugName(long ptr); private static native long nativeGetStringBlock(long ptr); @CriticalNative private static native boolean nativeIsUpToDate(long ptr); @CriticalNative private static native int nativeIsUpToDate(long ptr); private static native long nativeOpenXml(long ptr, @NonNull String fileName) throws IOException; private static native @Nullable OverlayableInfo nativeGetOverlayableInfo(long ptr, String overlayableName) throws IOException; Loading core/jni/android_content_res_ApkAssets.cpp +5 −5 Original line number Diff line number Diff line Loading @@ -129,8 +129,8 @@ class LoaderAssetsProvider : public AssetsProvider { return debug_name_; } bool IsUpToDate() const override { return true; UpToDate IsUpToDate() const override { return UpToDate::Always; } ~LoaderAssetsProvider() override { Loading Loading @@ -443,10 +443,10 @@ static jlong NativeGetStringBlock(JNIEnv* /*env*/, jclass /*clazz*/, jlong ptr) return reinterpret_cast<jlong>(apk_assets->GetLoadedArsc()->GetStringPool()); } static jboolean NativeIsUpToDate(CRITICAL_JNI_PARAMS_COMMA jlong ptr) { static jint NativeIsUpToDate(CRITICAL_JNI_PARAMS_COMMA jlong ptr) { auto scoped_apk_assets = ScopedLock(ApkAssetsFromLong(ptr)); auto apk_assets = scoped_apk_assets->get(); return apk_assets->IsUpToDate() ? JNI_TRUE : JNI_FALSE; return (jint)apk_assets->IsUpToDate(); } static jlong NativeOpenXml(JNIEnv* env, jclass /*clazz*/, jlong ptr, jstring file_name) { Loading Loading @@ -558,7 +558,7 @@ static const JNINativeMethod gApkAssetsMethods[] = { {"nativeGetDebugName", "(J)Ljava/lang/String;", (void*)NativeGetDebugName}, {"nativeGetStringBlock", "(J)J", (void*)NativeGetStringBlock}, // @CriticalNative {"nativeIsUpToDate", "(J)Z", (void*)NativeIsUpToDate}, {"nativeIsUpToDate", "(J)I", (void*)NativeIsUpToDate}, {"nativeOpenXml", "(JLjava/lang/String;)J", (void*)NativeOpenXml}, {"nativeGetOverlayableInfo", "(JLjava/lang/String;)Landroid/content/om/OverlayableInfo;", (void*)NativeGetOverlayableInfo}, Loading libs/androidfw/ApkAssets.cpp +6 −3 Original line number Diff line number Diff line Loading @@ -162,10 +162,13 @@ const std::string& ApkAssets::GetDebugName() const { return assets_provider_->GetDebugName(); } bool ApkAssets::IsUpToDate() const { UpToDate ApkAssets::IsUpToDate() const { // Loaders are invalidated by the app, not the system, so assume they are up to date. return IsLoader() || ((!loaded_idmap_ || loaded_idmap_->IsUpToDate()) && assets_provider_->IsUpToDate()); if (IsLoader()) { return UpToDate::Always; } const auto idmap_res = loaded_idmap_ ? loaded_idmap_->IsUpToDate() : UpToDate::Always; return combine(idmap_res, [this] { return assets_provider_->IsUpToDate(); }); } } // namespace android libs/androidfw/AssetsProvider.cpp +26 −39 Original line number Diff line number Diff line Loading @@ -86,11 +86,9 @@ void ZipAssetsProvider::ZipCloser::operator()(ZipArchive* a) const { } ZipAssetsProvider::ZipAssetsProvider(ZipArchiveHandle handle, PathOrDebugName&& path, package_property_t flags, time_t last_mod_time) : zip_handle_(handle), name_(std::move(path)), flags_(flags), last_mod_time_(last_mod_time) {} package_property_t flags, ModDate last_mod_time) : zip_handle_(handle), name_(std::move(path)), flags_(flags), last_mod_time_(last_mod_time) { } std::unique_ptr<ZipAssetsProvider> ZipAssetsProvider::Create(std::string path, package_property_t flags, Loading @@ -104,10 +102,10 @@ std::unique_ptr<ZipAssetsProvider> ZipAssetsProvider::Create(std::string path, return {}; } struct stat sb{.st_mtime = -1}; ModDate mod_date = kInvalidModDate; // Skip all up-to-date checks if the file won't ever change. if (!isReadonlyFilesystem(path.c_str())) { if ((released_fd < 0 ? stat(path.c_str(), &sb) : fstat(released_fd, &sb)) < 0) { if (isKnownWritablePath(path.c_str()) || !isReadonlyFilesystem(GetFileDescriptor(handle))) { if (mod_date = getFileModDate(GetFileDescriptor(handle)); mod_date == kInvalidModDate) { // Stat requires execute permissions on all directories path to the file. If the process does // not have execute permissions on this file, allow the zip to be opened but IsUpToDate() will // always have to return true. Loading @@ -116,7 +114,7 @@ std::unique_ptr<ZipAssetsProvider> ZipAssetsProvider::Create(std::string path, } return std::unique_ptr<ZipAssetsProvider>( new ZipAssetsProvider(handle, PathOrDebugName::Path(std::move(path)), flags, sb.st_mtime)); new ZipAssetsProvider(handle, PathOrDebugName::Path(std::move(path)), flags, mod_date)); } std::unique_ptr<ZipAssetsProvider> ZipAssetsProvider::Create(base::unique_fd fd, Loading @@ -137,10 +135,10 @@ std::unique_ptr<ZipAssetsProvider> ZipAssetsProvider::Create(base::unique_fd fd, return {}; } struct stat sb{.st_mtime = -1}; ModDate mod_date = kInvalidModDate; // Skip all up-to-date checks if the file won't ever change. if (!isReadonlyFilesystem(released_fd)) { if (fstat(released_fd, &sb) < 0) { if (mod_date = getFileModDate(released_fd); mod_date == kInvalidModDate) { // Stat requires execute permissions on all directories path to the file. If the process does // not have execute permissions on this file, allow the zip to be opened but IsUpToDate() will // always have to return true. Loading @@ -150,7 +148,7 @@ std::unique_ptr<ZipAssetsProvider> ZipAssetsProvider::Create(base::unique_fd fd, } return std::unique_ptr<ZipAssetsProvider>(new ZipAssetsProvider( handle, PathOrDebugName::DebugName(std::move(friendly_name)), flags, sb.st_mtime)); handle, PathOrDebugName::DebugName(std::move(friendly_name)), flags, mod_date)); } std::unique_ptr<Asset> ZipAssetsProvider::OpenInternal(const std::string& path, Loading Loading @@ -282,21 +280,16 @@ const std::string& ZipAssetsProvider::GetDebugName() const { return name_.GetDebugName(); } bool ZipAssetsProvider::IsUpToDate() const { if (last_mod_time_ == -1) { return true; } struct stat sb{}; if (fstat(GetFileDescriptor(zip_handle_.get()), &sb) < 0) { // If fstat fails on the zip archive, return true so the zip archive the resource system does // attempt to refresh the ApkAsset. return true; UpToDate ZipAssetsProvider::IsUpToDate() const { if (last_mod_time_ == kInvalidModDate) { return UpToDate::Always; } return last_mod_time_ == sb.st_mtime; return fromBool(last_mod_time_ == getFileModDate(GetFileDescriptor(zip_handle_.get()))); } DirectoryAssetsProvider::DirectoryAssetsProvider(std::string&& path, time_t last_mod_time) : dir_(std::move(path)), last_mod_time_(last_mod_time) {} DirectoryAssetsProvider::DirectoryAssetsProvider(std::string&& path, ModDate last_mod_time) : dir_(std::move(path)), last_mod_time_(last_mod_time) { } std::unique_ptr<DirectoryAssetsProvider> DirectoryAssetsProvider::Create(std::string path) { struct stat sb; Loading @@ -317,7 +310,7 @@ std::unique_ptr<DirectoryAssetsProvider> DirectoryAssetsProvider::Create(std::st const bool isReadonly = isReadonlyFilesystem(path.c_str()); return std::unique_ptr<DirectoryAssetsProvider>( new DirectoryAssetsProvider(std::move(path), isReadonly ? -1 : sb.st_mtime)); new DirectoryAssetsProvider(std::move(path), isReadonly ? kInvalidModDate : getModDate(sb))); } std::unique_ptr<Asset> DirectoryAssetsProvider::OpenInternal(const std::string& path, Loading Loading @@ -346,17 +339,11 @@ const std::string& DirectoryAssetsProvider::GetDebugName() const { return dir_; } bool DirectoryAssetsProvider::IsUpToDate() const { if (last_mod_time_ == -1) { return true; UpToDate DirectoryAssetsProvider::IsUpToDate() const { if (last_mod_time_ == kInvalidModDate) { return UpToDate::Always; } struct stat sb; if (stat(dir_.c_str(), &sb) < 0) { // If stat fails on the zip archive, return true so the zip archive the resource system does // attempt to refresh the ApkAsset. return true; } return last_mod_time_ == sb.st_mtime; return fromBool(last_mod_time_ == getFileModDate(dir_.c_str())); } MultiAssetsProvider::MultiAssetsProvider(std::unique_ptr<AssetsProvider>&& primary, Loading Loading @@ -397,8 +384,8 @@ const std::string& MultiAssetsProvider::GetDebugName() const { return debug_name_; } bool MultiAssetsProvider::IsUpToDate() const { return primary_->IsUpToDate() && secondary_->IsUpToDate(); UpToDate MultiAssetsProvider::IsUpToDate() const { return combine(primary_->IsUpToDate(), [this] { return secondary_->IsUpToDate(); }); } EmptyAssetsProvider::EmptyAssetsProvider(std::optional<std::string>&& path) : Loading Loading @@ -442,8 +429,8 @@ const std::string& EmptyAssetsProvider::GetDebugName() const { return kEmpty; } bool EmptyAssetsProvider::IsUpToDate() const { return true; UpToDate EmptyAssetsProvider::IsUpToDate() const { return UpToDate::Always; } } // namespace android libs/androidfw/Idmap.cpp +15 −6 Original line number Diff line number Diff line Loading @@ -22,9 +22,10 @@ #include "android-base/logging.h" #include "android-base/stringprintf.h" #include "android-base/utf8.h" #include "androidfw/misc.h" #include "androidfw/AssetManager.h" #include "androidfw/ResourceTypes.h" #include "androidfw/Util.h" #include "androidfw/misc.h" #include "utils/ByteOrder.h" #include "utils/Trace.h" Loading Loading @@ -280,11 +281,16 @@ LoadedIdmap::LoadedIdmap(const std::string& idmap_path, const Idmap_header* head configurations_(configs), overlay_entries_(overlay_entries), string_pool_(std::move(string_pool)), idmap_fd_( android::base::utf8::open(idmap_path.c_str(), O_RDONLY | O_CLOEXEC | O_BINARY | O_PATH)), overlay_apk_path_(overlay_apk_path), target_apk_path_(target_apk_path), idmap_last_mod_time_(getFileModDate(idmap_fd_.get())) { idmap_last_mod_time_(kInvalidModDate) { if (!isReadonlyFilesystem(std::string(overlay_apk_path_).c_str()) || !(target_apk_path_ == AssetManager::TARGET_APK_PATH || isReadonlyFilesystem(std::string(target_apk_path_).c_str()))) { idmap_fd_.reset( android::base::utf8::open(idmap_path.c_str(), O_RDONLY | O_CLOEXEC | O_BINARY | O_PATH)); idmap_last_mod_time_ = getFileModDate(idmap_fd_); } } std::unique_ptr<LoadedIdmap> LoadedIdmap::Load(StringPiece idmap_path, StringPiece idmap_data) { Loading Loading @@ -405,8 +411,11 @@ std::unique_ptr<LoadedIdmap> LoadedIdmap::Load(StringPiece idmap_path, StringPie std::move(idmap_string_pool),*overlay_path, *target_path)); } bool LoadedIdmap::IsUpToDate() const { return idmap_last_mod_time_ == getFileModDate(idmap_fd_.get()); UpToDate LoadedIdmap::IsUpToDate() const { if (idmap_last_mod_time_ == kInvalidModDate) { return UpToDate::Always; } return fromBool(idmap_last_mod_time_ == getFileModDate(idmap_fd_.get())); } } // namespace android Loading
core/java/android/content/res/ApkAssets.java +49 −7 Original line number Diff line number Diff line Loading @@ -25,6 +25,7 @@ import android.content.res.loader.ResourcesProvider; import android.ravenwood.annotation.RavenwoodClassLoadHook; import android.ravenwood.annotation.RavenwoodKeepWholeClass; import android.text.TextUtils; import android.util.Log; import com.android.internal.annotations.GuardedBy; Loading @@ -50,6 +51,7 @@ import java.util.Objects; @RavenwoodKeepWholeClass @RavenwoodClassLoadHook(RavenwoodClassLoadHook.LIBANDROID_LOADING_HOOK) public final class ApkAssets { private static final boolean DEBUG = false; /** * The apk assets contains framework resource values specified by the system. Loading Loading @@ -134,6 +136,17 @@ public final class ApkAssets { @Nullable private final AssetsProvider mAssets; @NonNull private String mName; private static final int UPTODATE_FALSE = 0; private static final int UPTODATE_TRUE = 1; private static final int UPTODATE_ALWAYS_TRUE = 2; // Start with the only value that may change later and would force a native call to // double check it. private int mPreviousUpToDateResult = UPTODATE_TRUE; /** * Creates a new ApkAssets instance from the given path on disk. * Loading Loading @@ -304,7 +317,7 @@ public final class ApkAssets { private ApkAssets(@FormatType int format, @NonNull String path, @PropertyFlags int flags, @Nullable AssetsProvider assets) throws IOException { this(format, flags, assets); this(format, flags, assets, path); Objects.requireNonNull(path, "path"); mNativePtr = nativeLoad(format, path, flags, assets); mStringBlock = new StringBlock(nativeGetStringBlock(mNativePtr), true /*useSparse*/); Loading @@ -313,7 +326,7 @@ public final class ApkAssets { private ApkAssets(@FormatType int format, @NonNull FileDescriptor fd, @NonNull String friendlyName, @PropertyFlags int flags, @Nullable AssetsProvider assets) throws IOException { this(format, flags, assets); this(format, flags, assets, friendlyName); Objects.requireNonNull(fd, "fd"); Objects.requireNonNull(friendlyName, "friendlyName"); mNativePtr = nativeLoadFd(format, fd, friendlyName, flags, assets); Loading @@ -323,7 +336,7 @@ public final class ApkAssets { private ApkAssets(@FormatType int format, @NonNull FileDescriptor fd, @NonNull String friendlyName, long offset, long length, @PropertyFlags int flags, @Nullable AssetsProvider assets) throws IOException { this(format, flags, assets); this(format, flags, assets, friendlyName); Objects.requireNonNull(fd, "fd"); Objects.requireNonNull(friendlyName, "friendlyName"); mNativePtr = nativeLoadFdOffsets(format, fd, friendlyName, offset, length, flags, assets); Loading @@ -331,16 +344,17 @@ public final class ApkAssets { } private ApkAssets(@PropertyFlags int flags, @Nullable AssetsProvider assets) { this(FORMAT_APK, flags, assets); this(FORMAT_APK, flags, assets, "empty"); mNativePtr = nativeLoadEmpty(flags, assets); mStringBlock = null; } private ApkAssets(@FormatType int format, @PropertyFlags int flags, @Nullable AssetsProvider assets) { @Nullable AssetsProvider assets, @NonNull String name) { mFlags = flags; mAssets = assets; mIsOverlay = format == FORMAT_IDMAP; if (DEBUG) mName = name; } @UnsupportedAppUsage Loading Loading @@ -421,13 +435,41 @@ public final class ApkAssets { } } private static double intervalMs(long beginNs, long endNs) { return (endNs - beginNs) / 1000000.0; } /** * Returns false if the underlying APK was changed since this ApkAssets was loaded. */ public boolean isUpToDate() { // This function is performance-critical - it's called multiple times on every Resources // object creation, and on few other cache accesses - so it's important to avoid the native // call when we know for sure what it will return (which is the case for both ALWAYS_TRUE // and FALSE). if (mPreviousUpToDateResult != UPTODATE_TRUE) { return mPreviousUpToDateResult == UPTODATE_ALWAYS_TRUE; } final long beforeTs, afterLockTs, afterNativeTs, afterUnlockTs; if (DEBUG) beforeTs = System.nanoTime(); final int res; synchronized (this) { return nativeIsUpToDate(mNativePtr); if (DEBUG) afterLockTs = System.nanoTime(); res = nativeIsUpToDate(mNativePtr); if (DEBUG) afterNativeTs = System.nanoTime(); } if (DEBUG) { afterUnlockTs = System.nanoTime(); if (afterUnlockTs - beforeTs >= 10L * 1000000) { Log.d("ApkAssets", "isUpToDate(" + mName + ") took " + intervalMs(beforeTs, afterUnlockTs) + " ms: " + intervalMs(beforeTs, afterLockTs) + " / " + intervalMs(afterLockTs, afterNativeTs) + " / " + intervalMs(afterNativeTs, afterUnlockTs)); } } mPreviousUpToDateResult = res; return res != UPTODATE_FALSE; } public boolean isSystem() { Loading Loading @@ -487,7 +529,7 @@ public final class ApkAssets { private static native @NonNull String nativeGetAssetPath(long ptr); private static native @NonNull String nativeGetDebugName(long ptr); private static native long nativeGetStringBlock(long ptr); @CriticalNative private static native boolean nativeIsUpToDate(long ptr); @CriticalNative private static native int nativeIsUpToDate(long ptr); private static native long nativeOpenXml(long ptr, @NonNull String fileName) throws IOException; private static native @Nullable OverlayableInfo nativeGetOverlayableInfo(long ptr, String overlayableName) throws IOException; Loading
core/jni/android_content_res_ApkAssets.cpp +5 −5 Original line number Diff line number Diff line Loading @@ -129,8 +129,8 @@ class LoaderAssetsProvider : public AssetsProvider { return debug_name_; } bool IsUpToDate() const override { return true; UpToDate IsUpToDate() const override { return UpToDate::Always; } ~LoaderAssetsProvider() override { Loading Loading @@ -443,10 +443,10 @@ static jlong NativeGetStringBlock(JNIEnv* /*env*/, jclass /*clazz*/, jlong ptr) return reinterpret_cast<jlong>(apk_assets->GetLoadedArsc()->GetStringPool()); } static jboolean NativeIsUpToDate(CRITICAL_JNI_PARAMS_COMMA jlong ptr) { static jint NativeIsUpToDate(CRITICAL_JNI_PARAMS_COMMA jlong ptr) { auto scoped_apk_assets = ScopedLock(ApkAssetsFromLong(ptr)); auto apk_assets = scoped_apk_assets->get(); return apk_assets->IsUpToDate() ? JNI_TRUE : JNI_FALSE; return (jint)apk_assets->IsUpToDate(); } static jlong NativeOpenXml(JNIEnv* env, jclass /*clazz*/, jlong ptr, jstring file_name) { Loading Loading @@ -558,7 +558,7 @@ static const JNINativeMethod gApkAssetsMethods[] = { {"nativeGetDebugName", "(J)Ljava/lang/String;", (void*)NativeGetDebugName}, {"nativeGetStringBlock", "(J)J", (void*)NativeGetStringBlock}, // @CriticalNative {"nativeIsUpToDate", "(J)Z", (void*)NativeIsUpToDate}, {"nativeIsUpToDate", "(J)I", (void*)NativeIsUpToDate}, {"nativeOpenXml", "(JLjava/lang/String;)J", (void*)NativeOpenXml}, {"nativeGetOverlayableInfo", "(JLjava/lang/String;)Landroid/content/om/OverlayableInfo;", (void*)NativeGetOverlayableInfo}, Loading
libs/androidfw/ApkAssets.cpp +6 −3 Original line number Diff line number Diff line Loading @@ -162,10 +162,13 @@ const std::string& ApkAssets::GetDebugName() const { return assets_provider_->GetDebugName(); } bool ApkAssets::IsUpToDate() const { UpToDate ApkAssets::IsUpToDate() const { // Loaders are invalidated by the app, not the system, so assume they are up to date. return IsLoader() || ((!loaded_idmap_ || loaded_idmap_->IsUpToDate()) && assets_provider_->IsUpToDate()); if (IsLoader()) { return UpToDate::Always; } const auto idmap_res = loaded_idmap_ ? loaded_idmap_->IsUpToDate() : UpToDate::Always; return combine(idmap_res, [this] { return assets_provider_->IsUpToDate(); }); } } // namespace android
libs/androidfw/AssetsProvider.cpp +26 −39 Original line number Diff line number Diff line Loading @@ -86,11 +86,9 @@ void ZipAssetsProvider::ZipCloser::operator()(ZipArchive* a) const { } ZipAssetsProvider::ZipAssetsProvider(ZipArchiveHandle handle, PathOrDebugName&& path, package_property_t flags, time_t last_mod_time) : zip_handle_(handle), name_(std::move(path)), flags_(flags), last_mod_time_(last_mod_time) {} package_property_t flags, ModDate last_mod_time) : zip_handle_(handle), name_(std::move(path)), flags_(flags), last_mod_time_(last_mod_time) { } std::unique_ptr<ZipAssetsProvider> ZipAssetsProvider::Create(std::string path, package_property_t flags, Loading @@ -104,10 +102,10 @@ std::unique_ptr<ZipAssetsProvider> ZipAssetsProvider::Create(std::string path, return {}; } struct stat sb{.st_mtime = -1}; ModDate mod_date = kInvalidModDate; // Skip all up-to-date checks if the file won't ever change. if (!isReadonlyFilesystem(path.c_str())) { if ((released_fd < 0 ? stat(path.c_str(), &sb) : fstat(released_fd, &sb)) < 0) { if (isKnownWritablePath(path.c_str()) || !isReadonlyFilesystem(GetFileDescriptor(handle))) { if (mod_date = getFileModDate(GetFileDescriptor(handle)); mod_date == kInvalidModDate) { // Stat requires execute permissions on all directories path to the file. If the process does // not have execute permissions on this file, allow the zip to be opened but IsUpToDate() will // always have to return true. Loading @@ -116,7 +114,7 @@ std::unique_ptr<ZipAssetsProvider> ZipAssetsProvider::Create(std::string path, } return std::unique_ptr<ZipAssetsProvider>( new ZipAssetsProvider(handle, PathOrDebugName::Path(std::move(path)), flags, sb.st_mtime)); new ZipAssetsProvider(handle, PathOrDebugName::Path(std::move(path)), flags, mod_date)); } std::unique_ptr<ZipAssetsProvider> ZipAssetsProvider::Create(base::unique_fd fd, Loading @@ -137,10 +135,10 @@ std::unique_ptr<ZipAssetsProvider> ZipAssetsProvider::Create(base::unique_fd fd, return {}; } struct stat sb{.st_mtime = -1}; ModDate mod_date = kInvalidModDate; // Skip all up-to-date checks if the file won't ever change. if (!isReadonlyFilesystem(released_fd)) { if (fstat(released_fd, &sb) < 0) { if (mod_date = getFileModDate(released_fd); mod_date == kInvalidModDate) { // Stat requires execute permissions on all directories path to the file. If the process does // not have execute permissions on this file, allow the zip to be opened but IsUpToDate() will // always have to return true. Loading @@ -150,7 +148,7 @@ std::unique_ptr<ZipAssetsProvider> ZipAssetsProvider::Create(base::unique_fd fd, } return std::unique_ptr<ZipAssetsProvider>(new ZipAssetsProvider( handle, PathOrDebugName::DebugName(std::move(friendly_name)), flags, sb.st_mtime)); handle, PathOrDebugName::DebugName(std::move(friendly_name)), flags, mod_date)); } std::unique_ptr<Asset> ZipAssetsProvider::OpenInternal(const std::string& path, Loading Loading @@ -282,21 +280,16 @@ const std::string& ZipAssetsProvider::GetDebugName() const { return name_.GetDebugName(); } bool ZipAssetsProvider::IsUpToDate() const { if (last_mod_time_ == -1) { return true; } struct stat sb{}; if (fstat(GetFileDescriptor(zip_handle_.get()), &sb) < 0) { // If fstat fails on the zip archive, return true so the zip archive the resource system does // attempt to refresh the ApkAsset. return true; UpToDate ZipAssetsProvider::IsUpToDate() const { if (last_mod_time_ == kInvalidModDate) { return UpToDate::Always; } return last_mod_time_ == sb.st_mtime; return fromBool(last_mod_time_ == getFileModDate(GetFileDescriptor(zip_handle_.get()))); } DirectoryAssetsProvider::DirectoryAssetsProvider(std::string&& path, time_t last_mod_time) : dir_(std::move(path)), last_mod_time_(last_mod_time) {} DirectoryAssetsProvider::DirectoryAssetsProvider(std::string&& path, ModDate last_mod_time) : dir_(std::move(path)), last_mod_time_(last_mod_time) { } std::unique_ptr<DirectoryAssetsProvider> DirectoryAssetsProvider::Create(std::string path) { struct stat sb; Loading @@ -317,7 +310,7 @@ std::unique_ptr<DirectoryAssetsProvider> DirectoryAssetsProvider::Create(std::st const bool isReadonly = isReadonlyFilesystem(path.c_str()); return std::unique_ptr<DirectoryAssetsProvider>( new DirectoryAssetsProvider(std::move(path), isReadonly ? -1 : sb.st_mtime)); new DirectoryAssetsProvider(std::move(path), isReadonly ? kInvalidModDate : getModDate(sb))); } std::unique_ptr<Asset> DirectoryAssetsProvider::OpenInternal(const std::string& path, Loading Loading @@ -346,17 +339,11 @@ const std::string& DirectoryAssetsProvider::GetDebugName() const { return dir_; } bool DirectoryAssetsProvider::IsUpToDate() const { if (last_mod_time_ == -1) { return true; UpToDate DirectoryAssetsProvider::IsUpToDate() const { if (last_mod_time_ == kInvalidModDate) { return UpToDate::Always; } struct stat sb; if (stat(dir_.c_str(), &sb) < 0) { // If stat fails on the zip archive, return true so the zip archive the resource system does // attempt to refresh the ApkAsset. return true; } return last_mod_time_ == sb.st_mtime; return fromBool(last_mod_time_ == getFileModDate(dir_.c_str())); } MultiAssetsProvider::MultiAssetsProvider(std::unique_ptr<AssetsProvider>&& primary, Loading Loading @@ -397,8 +384,8 @@ const std::string& MultiAssetsProvider::GetDebugName() const { return debug_name_; } bool MultiAssetsProvider::IsUpToDate() const { return primary_->IsUpToDate() && secondary_->IsUpToDate(); UpToDate MultiAssetsProvider::IsUpToDate() const { return combine(primary_->IsUpToDate(), [this] { return secondary_->IsUpToDate(); }); } EmptyAssetsProvider::EmptyAssetsProvider(std::optional<std::string>&& path) : Loading Loading @@ -442,8 +429,8 @@ const std::string& EmptyAssetsProvider::GetDebugName() const { return kEmpty; } bool EmptyAssetsProvider::IsUpToDate() const { return true; UpToDate EmptyAssetsProvider::IsUpToDate() const { return UpToDate::Always; } } // namespace android
libs/androidfw/Idmap.cpp +15 −6 Original line number Diff line number Diff line Loading @@ -22,9 +22,10 @@ #include "android-base/logging.h" #include "android-base/stringprintf.h" #include "android-base/utf8.h" #include "androidfw/misc.h" #include "androidfw/AssetManager.h" #include "androidfw/ResourceTypes.h" #include "androidfw/Util.h" #include "androidfw/misc.h" #include "utils/ByteOrder.h" #include "utils/Trace.h" Loading Loading @@ -280,11 +281,16 @@ LoadedIdmap::LoadedIdmap(const std::string& idmap_path, const Idmap_header* head configurations_(configs), overlay_entries_(overlay_entries), string_pool_(std::move(string_pool)), idmap_fd_( android::base::utf8::open(idmap_path.c_str(), O_RDONLY | O_CLOEXEC | O_BINARY | O_PATH)), overlay_apk_path_(overlay_apk_path), target_apk_path_(target_apk_path), idmap_last_mod_time_(getFileModDate(idmap_fd_.get())) { idmap_last_mod_time_(kInvalidModDate) { if (!isReadonlyFilesystem(std::string(overlay_apk_path_).c_str()) || !(target_apk_path_ == AssetManager::TARGET_APK_PATH || isReadonlyFilesystem(std::string(target_apk_path_).c_str()))) { idmap_fd_.reset( android::base::utf8::open(idmap_path.c_str(), O_RDONLY | O_CLOEXEC | O_BINARY | O_PATH)); idmap_last_mod_time_ = getFileModDate(idmap_fd_); } } std::unique_ptr<LoadedIdmap> LoadedIdmap::Load(StringPiece idmap_path, StringPiece idmap_data) { Loading Loading @@ -405,8 +411,11 @@ std::unique_ptr<LoadedIdmap> LoadedIdmap::Load(StringPiece idmap_path, StringPie std::move(idmap_string_pool),*overlay_path, *target_path)); } bool LoadedIdmap::IsUpToDate() const { return idmap_last_mod_time_ == getFileModDate(idmap_fd_.get()); UpToDate LoadedIdmap::IsUpToDate() const { if (idmap_last_mod_time_ == kInvalidModDate) { return UpToDate::Always; } return fromBool(idmap_last_mod_time_ == getFileModDate(idmap_fd_.get())); } } // namespace android