Loading api/system-current.txt +5 −0 Original line number Diff line number Diff line Loading @@ -9169,7 +9169,12 @@ package android.os.storage { method @WorkerThread public void allocateBytes(java.io.FileDescriptor, long, @RequiresPermission int) throws java.io.IOException; method @WorkerThread public long getAllocatableBytes(@NonNull java.util.UUID, @RequiresPermission int) throws java.io.IOException; method public static boolean hasIsolatedStorage(); method public void updateExternalStorageFileQuotaType(@NonNull java.io.File, int) throws java.io.IOException; field @RequiresPermission(android.Manifest.permission.ALLOCATE_AGGRESSIVE) public static final int FLAG_ALLOCATE_AGGRESSIVE = 1; // 0x1 field public static final int QUOTA_TYPE_MEDIA_AUDIO = 2; // 0x2 field public static final int QUOTA_TYPE_MEDIA_IMAGE = 1; // 0x1 field public static final int QUOTA_TYPE_MEDIA_NONE = 0; // 0x0 field public static final int QUOTA_TYPE_MEDIA_VIDEO = 3; // 0x3 } public final class StorageVolume implements android.os.Parcelable { core/java/android/os/storage/StorageManager.java +115 −0 Original line number Diff line number Diff line Loading @@ -2309,6 +2309,121 @@ public class StorageManager { private static final String XATTR_CACHE_GROUP = "user.cache_group"; private static final String XATTR_CACHE_TOMBSTONE = "user.cache_tombstone"; // Matches AID_MEDIA_RW in android_filesystem_config.h private static final int QUOTA_PROJECT_ID_MEDIA_NONE = 1023; // Matches AID_MEDIA_IMAGE in android_filesystem_config.h private static final int QUOTA_PROJECT_ID_MEDIA_IMAGE = 1057; // Matches AID_MEDIA_AUDIO in android_filesystem_config.h private static final int QUOTA_PROJECT_ID_MEDIA_AUDIO = 1055; // Matches AID_MEDIA_VIDEO in android_filesystem_config.h private static final int QUOTA_PROJECT_ID_MEDIA_VIDEO = 1056; /** * Constant for use with * {@link #updateExternalStorageFileQuotaType(String, int)} (String, int)}, to indicate the file * is not a media file. * * @hide */ @SystemApi public static final int QUOTA_TYPE_MEDIA_NONE = 0; /** * Constant for use with * {@link #updateExternalStorageFileQuotaType(String, int)} (String, int)}, to indicate the file * is an image file. * * @hide */ @SystemApi public static final int QUOTA_TYPE_MEDIA_IMAGE = 1; /** * Constant for use with * {@link #updateExternalStorageFileQuotaType(String, int)} (String, int)}, to indicate the file * is an audio file. * * @hide */ @SystemApi public static final int QUOTA_TYPE_MEDIA_AUDIO = 2; /** * Constant for use with * {@link #updateExternalStorageFileQuotaType(String, int)} (String, int)}, to indicate the file * is a video file. * * @hide */ @SystemApi public static final int QUOTA_TYPE_MEDIA_VIDEO = 3; /** @hide */ @Retention(RetentionPolicy.SOURCE) @IntDef(prefix = { "QUOTA_TYPE_" }, value = { QUOTA_TYPE_MEDIA_NONE, QUOTA_TYPE_MEDIA_AUDIO, QUOTA_TYPE_MEDIA_VIDEO, QUOTA_TYPE_MEDIA_IMAGE, }) public @interface QuotaType {} private static native boolean setQuotaProjectId(String path, long projectId); /** * Let StorageManager know that the quota type for a file on external storage should * be updated. Android tracks quotas for various media types. Consequently, this should be * called on first creation of a new file on external storage, and whenever the * media type of the file is updated later. * * This API doesn't require any special permissions, though typical implementations * will require being called from an SELinux domain that allows setting file attributes * related to quota (eg the GID or project ID). * * The default platform user of this API is the MediaProvider process, which is * responsible for managing all of external storage. * * @param path the path to the file for which we should update the quota type * @param quotaType the quota type of the file; this is based on the * {@code QuotaType} constants, eg * {@code StorageManager.QUOTA_TYPE_MEDIA_AUDIO} * * @throws IllegalArgumentException if {@code quotaType} does not correspond to a valid * quota type. * @throws IOException if the quota type could not be updated. * * @hide */ @SystemApi public void updateExternalStorageFileQuotaType(@NonNull File path, @QuotaType int quotaType) throws IOException { long projectId; final String filePath = path.getCanonicalPath(); switch (quotaType) { case QUOTA_TYPE_MEDIA_NONE: projectId = QUOTA_PROJECT_ID_MEDIA_NONE; break; case QUOTA_TYPE_MEDIA_AUDIO: projectId = QUOTA_PROJECT_ID_MEDIA_AUDIO; break; case QUOTA_TYPE_MEDIA_VIDEO: projectId = QUOTA_PROJECT_ID_MEDIA_VIDEO; break; case QUOTA_TYPE_MEDIA_IMAGE: projectId = QUOTA_PROJECT_ID_MEDIA_IMAGE; break; default: throw new IllegalArgumentException("Invalid quota type: " + quotaType); } if (!setQuotaProjectId(filePath, projectId)) { throw new IOException("Failed to update quota type for " + filePath); } } /** {@hide} */ private static void setCacheBehavior(File path, String name, boolean enabled) throws IOException { Loading core/jni/Android.bp +1 −0 Original line number Diff line number Diff line Loading @@ -137,6 +137,7 @@ cc_library_shared { "android_os_Parcel.cpp", "android_os_SELinux.cpp", "android_os_SharedMemory.cpp", "android_os_storage_StorageManager.cpp", "android_os_Trace.cpp", "android_os_UEventObserver.cpp", "android_os_VintfObject.cpp", Loading core/jni/AndroidRuntime.cpp +2 −0 Original line number Diff line number Diff line Loading @@ -143,6 +143,7 @@ extern int register_android_os_Parcel(JNIEnv* env); extern int register_android_os_SELinux(JNIEnv* env); extern int register_android_os_VintfObject(JNIEnv *env); extern int register_android_os_VintfRuntimeInfo(JNIEnv *env); extern int register_android_os_storage_StorageManager(JNIEnv* env); extern int register_android_os_SystemProperties(JNIEnv *env); extern int register_android_os_SystemClock(JNIEnv* env); extern int register_android_os_Trace(JNIEnv* env); Loading Loading @@ -1466,6 +1467,7 @@ static const RegJNIRec gRegJNI[] = { REG_JNI(register_android_os_HwParcel), REG_JNI(register_android_os_HwRemoteBinder), REG_JNI(register_android_os_NativeHandle), REG_JNI(register_android_os_storage_StorageManager), REG_JNI(register_android_os_VintfObject), REG_JNI(register_android_os_VintfRuntimeInfo), REG_JNI(register_android_service_DataLoaderService), Loading core/jni/android_os_storage_StorageManager.cpp 0 → 100644 +77 −0 Original line number Diff line number Diff line /* * Copyright (C) 2020 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 LOG_TAG "StorageManager" #include <android-base/logging.h> #include <android-base/unique_fd.h> #include <fcntl.h> #include <linux/fs.h> #include <nativehelper/JNIHelp.h> #include "core_jni_helpers.h" namespace android { jboolean android_os_storage_StorageManager_setQuotaProjectId(JNIEnv* env, jobject self, jstring path, jlong projectId) { struct fsxattr fsx; ScopedUtfChars utf_chars_path(env, path); if (projectId > UINT32_MAX) { LOG(ERROR) << "Invalid project id: " << projectId; return JNI_FALSE; } android::base::unique_fd fd( TEMP_FAILURE_RETRY(open(utf_chars_path.c_str(), O_RDONLY | O_CLOEXEC))); if (fd == -1) { PLOG(ERROR) << "Failed to open " << utf_chars_path.c_str() << " to set project id."; return JNI_FALSE; } int ret = ioctl(fd, FS_IOC_FSGETXATTR, &fsx); if (ret == -1) { PLOG(ERROR) << "Failed to get extended attributes for " << utf_chars_path.c_str() << " to get project id."; return JNI_FALSE; } fsx.fsx_projid = projectId; ret = ioctl(fd, FS_IOC_FSSETXATTR, &fsx); if (ret == -1) { PLOG(ERROR) << "Failed to set extended attributes for " << utf_chars_path.c_str() << " to set project id."; return JNI_FALSE; } return JNI_TRUE; } // ---------------------------------------------------------------------------- static const JNINativeMethod gStorageManagerMethods[] = { {"setQuotaProjectId", "(Ljava/lang/String;J)Z", (void*)android_os_storage_StorageManager_setQuotaProjectId}, }; const char* const kStorageManagerPathName = "android/os/storage/StorageManager"; int register_android_os_storage_StorageManager(JNIEnv* env) { return RegisterMethodsOrDie(env, kStorageManagerPathName, gStorageManagerMethods, NELEM(gStorageManagerMethods)); } }; // namespace android Loading
api/system-current.txt +5 −0 Original line number Diff line number Diff line Loading @@ -9169,7 +9169,12 @@ package android.os.storage { method @WorkerThread public void allocateBytes(java.io.FileDescriptor, long, @RequiresPermission int) throws java.io.IOException; method @WorkerThread public long getAllocatableBytes(@NonNull java.util.UUID, @RequiresPermission int) throws java.io.IOException; method public static boolean hasIsolatedStorage(); method public void updateExternalStorageFileQuotaType(@NonNull java.io.File, int) throws java.io.IOException; field @RequiresPermission(android.Manifest.permission.ALLOCATE_AGGRESSIVE) public static final int FLAG_ALLOCATE_AGGRESSIVE = 1; // 0x1 field public static final int QUOTA_TYPE_MEDIA_AUDIO = 2; // 0x2 field public static final int QUOTA_TYPE_MEDIA_IMAGE = 1; // 0x1 field public static final int QUOTA_TYPE_MEDIA_NONE = 0; // 0x0 field public static final int QUOTA_TYPE_MEDIA_VIDEO = 3; // 0x3 } public final class StorageVolume implements android.os.Parcelable {
core/java/android/os/storage/StorageManager.java +115 −0 Original line number Diff line number Diff line Loading @@ -2309,6 +2309,121 @@ public class StorageManager { private static final String XATTR_CACHE_GROUP = "user.cache_group"; private static final String XATTR_CACHE_TOMBSTONE = "user.cache_tombstone"; // Matches AID_MEDIA_RW in android_filesystem_config.h private static final int QUOTA_PROJECT_ID_MEDIA_NONE = 1023; // Matches AID_MEDIA_IMAGE in android_filesystem_config.h private static final int QUOTA_PROJECT_ID_MEDIA_IMAGE = 1057; // Matches AID_MEDIA_AUDIO in android_filesystem_config.h private static final int QUOTA_PROJECT_ID_MEDIA_AUDIO = 1055; // Matches AID_MEDIA_VIDEO in android_filesystem_config.h private static final int QUOTA_PROJECT_ID_MEDIA_VIDEO = 1056; /** * Constant for use with * {@link #updateExternalStorageFileQuotaType(String, int)} (String, int)}, to indicate the file * is not a media file. * * @hide */ @SystemApi public static final int QUOTA_TYPE_MEDIA_NONE = 0; /** * Constant for use with * {@link #updateExternalStorageFileQuotaType(String, int)} (String, int)}, to indicate the file * is an image file. * * @hide */ @SystemApi public static final int QUOTA_TYPE_MEDIA_IMAGE = 1; /** * Constant for use with * {@link #updateExternalStorageFileQuotaType(String, int)} (String, int)}, to indicate the file * is an audio file. * * @hide */ @SystemApi public static final int QUOTA_TYPE_MEDIA_AUDIO = 2; /** * Constant for use with * {@link #updateExternalStorageFileQuotaType(String, int)} (String, int)}, to indicate the file * is a video file. * * @hide */ @SystemApi public static final int QUOTA_TYPE_MEDIA_VIDEO = 3; /** @hide */ @Retention(RetentionPolicy.SOURCE) @IntDef(prefix = { "QUOTA_TYPE_" }, value = { QUOTA_TYPE_MEDIA_NONE, QUOTA_TYPE_MEDIA_AUDIO, QUOTA_TYPE_MEDIA_VIDEO, QUOTA_TYPE_MEDIA_IMAGE, }) public @interface QuotaType {} private static native boolean setQuotaProjectId(String path, long projectId); /** * Let StorageManager know that the quota type for a file on external storage should * be updated. Android tracks quotas for various media types. Consequently, this should be * called on first creation of a new file on external storage, and whenever the * media type of the file is updated later. * * This API doesn't require any special permissions, though typical implementations * will require being called from an SELinux domain that allows setting file attributes * related to quota (eg the GID or project ID). * * The default platform user of this API is the MediaProvider process, which is * responsible for managing all of external storage. * * @param path the path to the file for which we should update the quota type * @param quotaType the quota type of the file; this is based on the * {@code QuotaType} constants, eg * {@code StorageManager.QUOTA_TYPE_MEDIA_AUDIO} * * @throws IllegalArgumentException if {@code quotaType} does not correspond to a valid * quota type. * @throws IOException if the quota type could not be updated. * * @hide */ @SystemApi public void updateExternalStorageFileQuotaType(@NonNull File path, @QuotaType int quotaType) throws IOException { long projectId; final String filePath = path.getCanonicalPath(); switch (quotaType) { case QUOTA_TYPE_MEDIA_NONE: projectId = QUOTA_PROJECT_ID_MEDIA_NONE; break; case QUOTA_TYPE_MEDIA_AUDIO: projectId = QUOTA_PROJECT_ID_MEDIA_AUDIO; break; case QUOTA_TYPE_MEDIA_VIDEO: projectId = QUOTA_PROJECT_ID_MEDIA_VIDEO; break; case QUOTA_TYPE_MEDIA_IMAGE: projectId = QUOTA_PROJECT_ID_MEDIA_IMAGE; break; default: throw new IllegalArgumentException("Invalid quota type: " + quotaType); } if (!setQuotaProjectId(filePath, projectId)) { throw new IOException("Failed to update quota type for " + filePath); } } /** {@hide} */ private static void setCacheBehavior(File path, String name, boolean enabled) throws IOException { Loading
core/jni/Android.bp +1 −0 Original line number Diff line number Diff line Loading @@ -137,6 +137,7 @@ cc_library_shared { "android_os_Parcel.cpp", "android_os_SELinux.cpp", "android_os_SharedMemory.cpp", "android_os_storage_StorageManager.cpp", "android_os_Trace.cpp", "android_os_UEventObserver.cpp", "android_os_VintfObject.cpp", Loading
core/jni/AndroidRuntime.cpp +2 −0 Original line number Diff line number Diff line Loading @@ -143,6 +143,7 @@ extern int register_android_os_Parcel(JNIEnv* env); extern int register_android_os_SELinux(JNIEnv* env); extern int register_android_os_VintfObject(JNIEnv *env); extern int register_android_os_VintfRuntimeInfo(JNIEnv *env); extern int register_android_os_storage_StorageManager(JNIEnv* env); extern int register_android_os_SystemProperties(JNIEnv *env); extern int register_android_os_SystemClock(JNIEnv* env); extern int register_android_os_Trace(JNIEnv* env); Loading Loading @@ -1466,6 +1467,7 @@ static const RegJNIRec gRegJNI[] = { REG_JNI(register_android_os_HwParcel), REG_JNI(register_android_os_HwRemoteBinder), REG_JNI(register_android_os_NativeHandle), REG_JNI(register_android_os_storage_StorageManager), REG_JNI(register_android_os_VintfObject), REG_JNI(register_android_os_VintfRuntimeInfo), REG_JNI(register_android_service_DataLoaderService), Loading
core/jni/android_os_storage_StorageManager.cpp 0 → 100644 +77 −0 Original line number Diff line number Diff line /* * Copyright (C) 2020 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 LOG_TAG "StorageManager" #include <android-base/logging.h> #include <android-base/unique_fd.h> #include <fcntl.h> #include <linux/fs.h> #include <nativehelper/JNIHelp.h> #include "core_jni_helpers.h" namespace android { jboolean android_os_storage_StorageManager_setQuotaProjectId(JNIEnv* env, jobject self, jstring path, jlong projectId) { struct fsxattr fsx; ScopedUtfChars utf_chars_path(env, path); if (projectId > UINT32_MAX) { LOG(ERROR) << "Invalid project id: " << projectId; return JNI_FALSE; } android::base::unique_fd fd( TEMP_FAILURE_RETRY(open(utf_chars_path.c_str(), O_RDONLY | O_CLOEXEC))); if (fd == -1) { PLOG(ERROR) << "Failed to open " << utf_chars_path.c_str() << " to set project id."; return JNI_FALSE; } int ret = ioctl(fd, FS_IOC_FSGETXATTR, &fsx); if (ret == -1) { PLOG(ERROR) << "Failed to get extended attributes for " << utf_chars_path.c_str() << " to get project id."; return JNI_FALSE; } fsx.fsx_projid = projectId; ret = ioctl(fd, FS_IOC_FSSETXATTR, &fsx); if (ret == -1) { PLOG(ERROR) << "Failed to set extended attributes for " << utf_chars_path.c_str() << " to set project id."; return JNI_FALSE; } return JNI_TRUE; } // ---------------------------------------------------------------------------- static const JNINativeMethod gStorageManagerMethods[] = { {"setQuotaProjectId", "(Ljava/lang/String;J)Z", (void*)android_os_storage_StorageManager_setQuotaProjectId}, }; const char* const kStorageManagerPathName = "android/os/storage/StorageManager"; int register_android_os_storage_StorageManager(JNIEnv* env) { return RegisterMethodsOrDie(env, kStorageManagerPathName, gStorageManagerMethods, NELEM(gStorageManagerMethods)); } }; // namespace android