| /* |
| * Copyright (C) 2019 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 specic language governing permissions and |
| * limitations under the License. |
| */ |
| |
| #ifndef MEDIAPROVIDER_FUSE_MEDIAPROVIDERWRAPPER_H_ |
| #define MEDIAPROVIDER_FUSE_MEDIAPROVIDERWRAPPER_H_ |
| |
| #include <android-base/logging.h> |
| #include <jni.h> |
| #include <sys/types.h> |
| |
| #include <dirent.h> |
| #include <atomic> |
| #include <condition_variable> |
| #include <functional> |
| #include <mutex> |
| #include <queue> |
| #include <string> |
| #include <thread> |
| |
| #include "libfuse_jni/ReaddirHelper.h" |
| #include "libfuse_jni/RedactionInfo.h" |
| |
| namespace mediaprovider { |
| namespace fuse { |
| |
| /** Represents file open result from MediaProvider */ |
| struct FileOpenResult { |
| FileOpenResult(const int status, const int uid, const uid_t transforms_uid, const int fd, |
| const RedactionInfo* redaction_info) |
| : status(status), |
| uid(uid), |
| transforms_uid(transforms_uid), |
| fd(fd), |
| redaction_info(redaction_info) {} |
| |
| const int status; |
| const int uid; |
| const uid_t transforms_uid; |
| const int fd; |
| std::unique_ptr<const RedactionInfo> redaction_info; |
| }; |
| |
| /** |
| * Represents transform info for a file, containing the transforms, the transforms completion |
| * status and the ioPath. Provided by MediaProvider.java via a JNI call. |
| */ |
| struct FileLookupResult { |
| FileLookupResult(int transforms, int transforms_reason, uid_t uid, bool transforms_complete, |
| bool transforms_supported, const std::string& io_path) |
| : transforms(transforms), |
| transforms_reason(transforms_reason), |
| uid(uid), |
| transforms_complete(transforms_complete), |
| transforms_supported(transforms_supported), |
| io_path(io_path) { |
| if (transforms != 0) { |
| CHECK(transforms_supported); |
| } |
| } |
| |
| /** |
| * These fields are not to be interpreted, they are determined and populated from MediaProvider |
| * via a JNI call. |
| */ |
| const int transforms; |
| const int transforms_reason; |
| const uid_t uid; |
| const bool transforms_complete; |
| const bool transforms_supported; |
| const std::string io_path; |
| }; |
| |
| /** |
| * Class that wraps MediaProvider.java and all of the needed JNI calls to make |
| * interaction with MediaProvider easier. |
| */ |
| class MediaProviderWrapper final { |
| public: |
| MediaProviderWrapper(JNIEnv* env, jobject media_provider); |
| ~MediaProviderWrapper(); |
| |
| /** |
| * Computes and returns the RedactionInfo for a given file and UID. |
| * |
| * @param uid UID of the app requesting the read |
| * @param path path of the requested file that will be used for database operations |
| * @param io_path path of the requested file that will be used for IO |
| * @return RedactionInfo on success, nullptr on failure to calculate |
| * redaction ranges (e.g. exception was thrown in Java world) |
| */ |
| std::unique_ptr<RedactionInfo> GetRedactionInfo(const std::string& path, |
| const std::string& io_path, uid_t uid, |
| pid_t tid); |
| |
| /** |
| * Inserts a new entry for the given path and UID. |
| * |
| * @param path the path of the file to be created |
| * @param uid UID of the calling app |
| * @return 0 if the operation succeeded, |
| * or errno error code if operation fails. |
| */ |
| int InsertFile(const std::string& path, uid_t uid); |
| |
| /** |
| * Delete the file denoted by the given path on behalf of the given UID. |
| * |
| * @param path the path of the file to be deleted |
| * @param uid UID of the calling app |
| * @return 0 upon success, or errno error code if operation fails. |
| */ |
| int DeleteFile(const std::string& path, uid_t uid); |
| |
| /** |
| * Gets directory entries for given path from MediaProvider database and lower file system |
| * |
| * @param uid UID of the calling app. |
| * @param path Relative path of the directory. |
| * @param dirp Pointer to directory stream, used to query lower file system. |
| * @return DirectoryEntries with list of directory entries on success. |
| * File names in a directory are obtained from MediaProvider. If a path is unknown to |
| * MediaProvider, file names are obtained from lower file system. All directory names in the |
| * given directory are obtained from lower file system. |
| * An empty string in first directory entry name indicates the error occurred while obtaining |
| * directory entries, directory entry type will hold the corresponding errno information. |
| */ |
| std::vector<std::shared_ptr<DirectoryEntry>> GetDirectoryEntries(uid_t uid, |
| const std::string& path, |
| DIR* dirp); |
| |
| /** |
| * Determines if the given UID is allowed to open the file denoted by the given path. |
| * |
| * Also computes and returns the RedactionInfo for a given file and |uid| |
| * |
| * @param path path of the requested file that will be used for database operations |
| * @param io_path path of the requested file that will be used for IO |
| * @param uid UID of the calling app |
| * @param tid UID of the calling app |
| * @param for_write specifies if the file is to be opened for write |
| * @param redact specifies whether to attempt redaction |
| * @return FileOpenResult containing status, uid and redaction_info |
| */ |
| std::unique_ptr<FileOpenResult> OnFileOpen(const std::string& path, const std::string& io_path, |
| uid_t uid, pid_t tid, int transforms_reason, |
| bool for_write, bool redact, |
| bool log_transforms_metrics); |
| |
| /** |
| * Determines if the given UID is allowed to create a directory with the given path. |
| * |
| * @param path the path of the directory to be created |
| * @param uid UID of the calling app |
| * @return 0 if it's allowed, or errno error code if operation isn't allowed. |
| */ |
| int IsCreatingDirAllowed(const std::string& path, uid_t uid); |
| |
| /** |
| * Determines if the given UID is allowed to delete the directory with the given path. |
| * |
| * @param path the path of the directory to be deleted |
| * @param uid UID of the calling app |
| * @return 0 if it's allowed, or errno error code if operation isn't allowed. |
| */ |
| int IsDeletingDirAllowed(const std::string& path, uid_t uid); |
| |
| /** |
| * Determines if the given UID is allowed to open the directory with the given path. |
| * |
| * @param path the path of the directory to be opened |
| * @param uid UID of the calling app |
| * @param forWrite if it's a write access |
| * @return 0 if it's allowed, or errno error code if operation isn't allowed. |
| */ |
| int IsOpendirAllowed(const std::string& path, uid_t uid, bool forWrite); |
| |
| /** |
| * Determines if one of the follows is true: |
| * 1. The package name of the given private path matches the given uid, |
| then this uid has access to private-app directories for this package. |
| * 2. The calling uid has special access to private-app directories: |
| * * DownloadProvider and ExternalStorageProvider has access to private |
| * app directories. |
| * * Installer apps have access to Android/obb directories |
| * |
| * @param uid UID of the app |
| * @param path the private path that the UID wants to access |
| * @return true if it matches, otherwise return false. |
| */ |
| bool isUidAllowedAccessToDataOrObbPath(uid_t uid, const std::string& path); |
| |
| /** |
| * Renames a file or directory to new path. |
| * |
| * @param old_path path of the file or directory to be renamed. |
| * @param new_path new path of the file or directory to be renamed. |
| * @param uid UID of the calling app. |
| * @return 0 if rename is successful, errno if one of the rename fails. If return |
| * value is 0, it's guaranteed that file/directory is moved to new_path. For any other errno |
| * except EFAULT/EIO, it's guaranteed that file/directory is not renamed. |
| */ |
| int Rename(const std::string& old_path, const std::string& new_path, uid_t uid); |
| |
| /** |
| * Called whenever a file has been created through FUSE. |
| * |
| * @param path path of the file that has been created. |
| */ |
| void OnFileCreated(const std::string& path); |
| |
| /** |
| * Returns FileLookupResult to determine transform info for a path and uid. |
| */ |
| std::unique_ptr<FileLookupResult> FileLookup(const std::string& path, uid_t uid, pid_t tid); |
| |
| /** Transforms from src to dst file */ |
| bool Transform(const std::string& src, const std::string& dst, int transforms, |
| int transforms_reason, uid_t read_uid, uid_t open_uid, uid_t transforms_uid); |
| |
| /** |
| * Determines if to allow FUSE_LOOKUP for uid. Might allow uids that don't belong to the |
| * MediaProvider user, depending on OEM configuration. |
| * |
| * @param uid linux uid to check |
| */ |
| bool ShouldAllowLookup(uid_t uid, int path_user_id); |
| |
| /** |
| * Determines if the passed in user ID is an app clone user (paired with user 0) |
| * |
| * @param userId the user ID to check |
| */ |
| bool IsAppCloneUser(uid_t userId); |
| |
| /** |
| * Initializes per-process static variables associated with the lifetime of |
| * a managed runtime. |
| */ |
| static void OneTimeInit(JavaVM* vm); |
| |
| /** TLS Key to map a given thread to its JNIEnv. */ |
| static pthread_key_t gJniEnvKey; |
| |
| private: |
| jclass file_lookup_result_class_; |
| jclass file_open_result_class_; |
| jclass media_provider_class_; |
| jobject media_provider_object_; |
| /** Cached MediaProvider method IDs **/ |
| jmethodID mid_insert_file_; |
| jmethodID mid_delete_file_; |
| jmethodID mid_on_file_open_; |
| jmethodID mid_scan_file_; |
| jmethodID mid_is_diraccess_allowed_; |
| jmethodID mid_get_files_in_dir_; |
| jmethodID mid_rename_; |
| jmethodID mid_is_uid_allowed_access_to_data_or_obb_path_; |
| jmethodID mid_on_file_created_; |
| jmethodID mid_should_allow_lookup_; |
| jmethodID mid_is_app_clone_user_; |
| jmethodID mid_transform_; |
| jmethodID mid_file_lookup_; |
| /** Cached FileLookupResult field IDs **/ |
| jfieldID fid_file_lookup_transforms_; |
| jfieldID fid_file_lookup_transforms_reason_; |
| jfieldID fid_file_lookup_uid_; |
| jfieldID fid_file_lookup_transforms_complete_; |
| jfieldID fid_file_lookup_transforms_supported_; |
| jfieldID fid_file_lookup_io_path_; |
| /** Cached FileOpenResult field IDs **/ |
| jfieldID fid_file_open_status_; |
| jfieldID fid_file_open_uid_; |
| jfieldID fid_file_open_transforms_uid_; |
| jfieldID fid_file_open_redaction_ranges_; |
| jfieldID fid_file_open_fd_; |
| |
| /** |
| * Auxiliary for caching MediaProvider methods. |
| */ |
| jmethodID CacheMethod(JNIEnv* env, const char method_name[], const char signature[]); |
| |
| // Attaches the current thread (if necessary) and returns the JNIEnv |
| // associated with it. |
| static JNIEnv* MaybeAttachCurrentThread(); |
| // Destructor function for a given native thread. Called precisely once |
| // by the pthreads library. |
| static void DetachThreadFunction(void* unused); |
| |
| static JavaVM* gJavaVm; |
| }; |
| |
| } // namespace fuse |
| } // namespace mediaprovider |
| |
| #endif // MEDIAPROVIDER_FUSE_MEDIAPROVIDERWRAPPER_H_ |