You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
305 lines
12 KiB
305 lines
12 KiB
/*
|
|
* 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, uid_t transforms_uid,
|
|
const RedactionInfo* redaction_info)
|
|
: status(status), uid(uid), transforms_uid(transforms_uid), redaction_info(redaction_info) {}
|
|
|
|
const int status;
|
|
const int uid;
|
|
const uid_t transforms_uid;
|
|
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_mkdir_or_rmdir_allowed_;
|
|
jmethodID mid_is_opendir_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_;
|
|
|
|
/**
|
|
* Auxiliary for caching MediaProvider methods.
|
|
*/
|
|
jmethodID CacheMethod(JNIEnv* env, const char method_name[], const char signature[],
|
|
bool is_static);
|
|
|
|
// 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_
|