blob: 2f3f6d13b0ff4a6dca32b1127f79adc581f62baf [file] [log] [blame]
/*
* 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 <jni.h>
#include <sys/types.h>
#include <atomic>
#include <condition_variable>
#include <functional>
#include <mutex>
#include <queue>
#include <string>
#include <thread>
#include "libfuse_jni/RedactionInfo.h"
namespace mediaprovider {
namespace fuse {
/**
* Type describing a JNI task, sent to the JNI thread.
* The function only takes JNIEnv because that's the parameter that JNI thread
* must provide. The rest of the arguments can be captured by the lambda,
* the return value should be captured by reference.
*/
typedef std::function<void(JNIEnv*)> JniTask;
/**
* 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 FD and UID.
*
* @param uid UID of the app requesting the read
* @param fd FD of the requested file
* @return RedactionInfo on success, nullptr on failure to calculate
* redaction ranges (e.g. exception was thrown in Java world)
*/
std::unique_ptr<RedactionInfo> GetRedactionInfo(uid_t uid, int fd);
private:
jclass media_provider_class_;
jobject media_provider_object_;
/** Add MediaProvider method IDs that you want to cache here **/
jmethodID mid_get_redaction_ranges_;
/**
* All JNI calls are delegated to this thread
*/
std::thread jni_thread_;
/**
* jniThread loops until d'tor is called, waiting for a notification on condition_variable to
* perform a task
*/
std::condition_variable pending_task_cond_;
/**
* Communication with jniThread is done through this JniTasks queue.
*/
std::queue<JniTask> jni_tasks_;
/**
* Threads can post a JNI task if and only if this is true.
*/
std::atomic<bool> jni_tasks_welcome_;
/**
* JNI thread keeps running until it finishes a task after which this value
* is set to false
*/
std::atomic<bool> jni_thread_terminated_;
/**
* All member variables prefixed with jni should be guarded by this lock.
*/
std::mutex jni_task_lock_;
/**
* Auxiliary for caching MediaProvider methods
*/
jmethodID CacheMethod(JNIEnv* env, const char method_name[], const char signature[],
bool is_static);
/**
* Main loop for the JNI thread
*/
void JniThreadLoop(JavaVM* jvm);
/**
* Mechanism for posting JNI tasks and waiting until they're done
*/
bool PostAndWaitForTask(const JniTask& t);
};
} // namespace fuse
} // namespace mediaprovider
#endif // MEDIAPROVIDER_FUSE_MEDIAPROVIDERWRAPPER_H_