blob: 54c7a87454c75b9dcd892d750696b96cee43f57d [file] [log] [blame]
Zim3e45d9b2019-08-19 21:14:14 +01001/*
2 * Copyright (C) 2019 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specic language governing permissions and
14 * limitations under the License.
15 */
16
17// Need to use LOGE_EX.
Zim7e0d3142019-10-17 21:06:12 +010018#define LOG_TAG "FuseDaemonJNI"
Zim3e45d9b2019-08-19 21:14:14 +010019
Zim763428f2021-09-17 11:46:48 +010020#include <nativehelper/scoped_local_ref.h>
shafik8b57cd52019-09-06 10:51:29 +010021#include <nativehelper/scoped_utf_chars.h>
Zim3e45d9b2019-08-19 21:14:14 +010022
23#include <string>
24
shafik8b57cd52019-09-06 10:51:29 +010025#include "FuseDaemon.h"
Narayan Kamathde3fe172020-02-18 12:14:51 +000026#include "MediaProviderWrapper.h"
shafik8b57cd52019-09-06 10:51:29 +010027#include "android-base/logging.h"
Martijn Coenen083eb692020-04-24 09:39:58 +020028#include "android-base/unique_fd.h"
Zim3e45d9b2019-08-19 21:14:14 +010029
30namespace mediaprovider {
31namespace {
32
Zim08041a82022-01-13 15:43:38 +000033constexpr const char* FUSE_DAEMON_CLASS_NAME = "com/android/providers/media/fuse/FuseDaemon";
34constexpr const char* FD_ACCESS_RESULT_CLASS_NAME = "com/android/providers/media/FdAccessResult";
Zim3e45d9b2019-08-19 21:14:14 +010035static jclass gFuseDaemonClass;
Zim08041a82022-01-13 15:43:38 +000036static jclass gFdAccessResultClass;
37static jmethodID gFdAccessResultCtor;
Zim3e45d9b2019-08-19 21:14:14 +010038
Zim763428f2021-09-17 11:46:48 +010039static std::vector<std::string> get_supported_transcoding_relative_paths(
40 JNIEnv* env, jobjectArray java_supported_transcoding_relative_paths) {
41 ScopedLocalRef<jobjectArray> j_transcoding_relative_paths(
42 env, java_supported_transcoding_relative_paths);
43 std::vector<std::string> transcoding_relative_paths;
44
45 const int transcoding_relative_paths_count =
46 env->GetArrayLength(j_transcoding_relative_paths.get());
47 for (int i = 0; i < transcoding_relative_paths_count; i++) {
48 ScopedLocalRef<jstring> j_ref_relative_path(
49 env, (jstring)env->GetObjectArrayElement(j_transcoding_relative_paths.get(), i));
50 ScopedUtfChars j_utf_relative_path(env, j_ref_relative_path.get());
51 const char* relative_path = j_utf_relative_path.c_str();
52
53 if (relative_path) {
54 transcoding_relative_paths.push_back(relative_path);
55 } else {
56 LOG(ERROR) << "Error reading supported transcoding relative path at index: " << i;
57 }
58 }
59
60 return transcoding_relative_paths;
61}
62
Zimedbe69e2019-12-13 18:49:36 +000063jlong com_android_providers_media_FuseDaemon_new(JNIEnv* env, jobject self,
64 jobject media_provider) {
Narayan Kamath88203dc2019-08-30 17:19:38 +010065 LOG(DEBUG) << "Creating the FUSE daemon...";
Zimedbe69e2019-12-13 18:49:36 +000066 return reinterpret_cast<jlong>(new fuse::FuseDaemon(env, media_provider));
Zim3e45d9b2019-08-19 21:14:14 +010067}
68
Zim763428f2021-09-17 11:46:48 +010069void com_android_providers_media_FuseDaemon_start(
70 JNIEnv* env, jobject self, jlong java_daemon, jint fd, jstring java_path,
71 jobjectArray java_supported_transcoding_relative_paths) {
Narayan Kamath88203dc2019-08-30 17:19:38 +010072 LOG(DEBUG) << "Starting the FUSE daemon...";
Zim3e45d9b2019-08-19 21:14:14 +010073 fuse::FuseDaemon* const daemon = reinterpret_cast<fuse::FuseDaemon*>(java_daemon);
74
Martijn Coenen083eb692020-04-24 09:39:58 +020075 android::base::unique_fd ufd(fd);
76
Zim7c8712d2019-10-03 21:01:26 +010077 ScopedUtfChars utf_chars_path(env, java_path);
78 if (!utf_chars_path.c_str()) {
Zim3e45d9b2019-08-19 21:14:14 +010079 return;
80 }
Zim3e45d9b2019-08-19 21:14:14 +010081
Zim763428f2021-09-17 11:46:48 +010082 const std::vector<std::string>& transcoding_relative_paths =
83 get_supported_transcoding_relative_paths(env,
84 java_supported_transcoding_relative_paths);
85
86 daemon->Start(std::move(ufd), utf_chars_path.c_str(), transcoding_relative_paths);
Zim3e45d9b2019-08-19 21:14:14 +010087}
88
Zimd0435b22020-03-05 13:52:51 +000089bool com_android_providers_media_FuseDaemon_is_started(JNIEnv* env, jobject self,
90 jlong java_daemon) {
91 LOG(DEBUG) << "Checking if FUSE daemon started...";
92 const fuse::FuseDaemon* daemon = reinterpret_cast<fuse::FuseDaemon*>(java_daemon);
93 return daemon->IsStarted();
94}
95
shafik8b57cd52019-09-06 10:51:29 +010096void com_android_providers_media_FuseDaemon_delete(JNIEnv* env, jobject self, jlong java_daemon) {
Narayan Kamath88203dc2019-08-30 17:19:38 +010097 LOG(DEBUG) << "Destroying the FUSE daemon...";
Zim3e45d9b2019-08-19 21:14:14 +010098 fuse::FuseDaemon* const daemon = reinterpret_cast<fuse::FuseDaemon*>(java_daemon);
99 delete daemon;
100}
101
Zimedbe69e2019-12-13 18:49:36 +0000102jboolean com_android_providers_media_FuseDaemon_should_open_with_fuse(JNIEnv* env, jobject self,
103 jlong java_daemon,
104 jstring java_path,
105 jboolean for_read, jint fd) {
106 fuse::FuseDaemon* const daemon = reinterpret_cast<fuse::FuseDaemon*>(java_daemon);
107 if (daemon) {
108 ScopedUtfChars utf_chars_path(env, java_path);
109 if (!utf_chars_path.c_str()) {
110 // TODO(b/145741852): Throw exception
111 return JNI_FALSE;
112 }
113
114 return daemon->ShouldOpenWithFuse(fd, for_read, utf_chars_path.c_str());
115 }
116 // TODO(b/145741852): Throw exception
117 return JNI_FALSE;
118}
119
Zima76c3492020-02-19 01:23:26 +0000120void com_android_providers_media_FuseDaemon_invalidate_fuse_dentry_cache(JNIEnv* env, jobject self,
121 jlong java_daemon,
122 jstring java_path) {
123 fuse::FuseDaemon* const daemon = reinterpret_cast<fuse::FuseDaemon*>(java_daemon);
124 if (daemon) {
125 ScopedUtfChars utf_chars_path(env, java_path);
126 if (!utf_chars_path.c_str()) {
127 // TODO(b/145741152): Throw exception
128 return;
129 }
130
Colin Cross915ad6a2020-04-03 18:19:07 -0700131 CHECK(pthread_getspecific(fuse::MediaProviderWrapper::gJniEnvKey) == nullptr);
Zima76c3492020-02-19 01:23:26 +0000132 daemon->InvalidateFuseDentryCache(utf_chars_path.c_str());
133 }
134 // TODO(b/145741152): Throw exception
135}
136
Zim08041a82022-01-13 15:43:38 +0000137jobject com_android_providers_media_FuseDaemon_check_fd_access(JNIEnv* env, jobject self,
138 jlong java_daemon, jint fd,
139 jint uid) {
Biswarup Pal93f4ec12021-02-15 13:39:36 +0000140 fuse::FuseDaemon* const daemon = reinterpret_cast<fuse::FuseDaemon*>(java_daemon);
Zim08041a82022-01-13 15:43:38 +0000141 const std::unique_ptr<fuse::FdAccessResult> result = daemon->CheckFdAccess(fd, uid);
142 return env->NewObject(gFdAccessResultClass, gFdAccessResultCtor,
143 env->NewStringUTF(result->file_path.c_str()), result->should_redact);
Biswarup Pal93f4ec12021-02-15 13:39:36 +0000144}
145
146void com_android_providers_media_FuseDaemon_initialize_device_id(JNIEnv* env, jobject self,
147 jlong java_daemon,
148 jstring java_path) {
149 fuse::FuseDaemon* const daemon = reinterpret_cast<fuse::FuseDaemon*>(java_daemon);
150 ScopedUtfChars utf_chars_path(env, java_path);
151 if (!utf_chars_path.c_str()) {
152 LOG(WARNING) << "Couldn't initialise FUSE device id";
153 return;
154 }
155 daemon->InitializeDeviceId(utf_chars_path.c_str());
156}
157
Zimc0e65bd2020-03-09 15:22:59 +0000158bool com_android_providers_media_FuseDaemon_is_fuse_thread(JNIEnv* env, jclass clazz) {
Zimc0e65bd2020-03-09 15:22:59 +0000159 return pthread_getspecific(fuse::MediaProviderWrapper::gJniEnvKey) != nullptr;
160}
161
Zim3e45d9b2019-08-19 21:14:14 +0100162const JNINativeMethod methods[] = {
Zim7c8712d2019-10-03 21:01:26 +0100163 {"native_new", "(Lcom/android/providers/media/MediaProvider;)J",
164 reinterpret_cast<void*>(com_android_providers_media_FuseDaemon_new)},
Zim763428f2021-09-17 11:46:48 +0100165 {"native_start", "(JILjava/lang/String;[Ljava/lang/String;)V",
Zim7c8712d2019-10-03 21:01:26 +0100166 reinterpret_cast<void*>(com_android_providers_media_FuseDaemon_start)},
Zim7c8712d2019-10-03 21:01:26 +0100167 {"native_delete", "(J)V",
Zimedbe69e2019-12-13 18:49:36 +0000168 reinterpret_cast<void*>(com_android_providers_media_FuseDaemon_delete)},
169 {"native_should_open_with_fuse", "(JLjava/lang/String;ZI)Z",
Zima76c3492020-02-19 01:23:26 +0000170 reinterpret_cast<void*>(com_android_providers_media_FuseDaemon_should_open_with_fuse)},
Zimc0e65bd2020-03-09 15:22:59 +0000171 {"native_is_fuse_thread", "()Z",
172 reinterpret_cast<void*>(com_android_providers_media_FuseDaemon_is_fuse_thread)},
Zimd0435b22020-03-05 13:52:51 +0000173 {"native_is_started", "(J)Z",
174 reinterpret_cast<void*>(com_android_providers_media_FuseDaemon_is_started)},
Zima76c3492020-02-19 01:23:26 +0000175 {"native_invalidate_fuse_dentry_cache", "(JLjava/lang/String;)V",
176 reinterpret_cast<void*>(
Biswarup Pal93f4ec12021-02-15 13:39:36 +0000177 com_android_providers_media_FuseDaemon_invalidate_fuse_dentry_cache)},
Zim08041a82022-01-13 15:43:38 +0000178 {"native_check_fd_access", "(JII)Lcom/android/providers/media/FdAccessResult;",
179 reinterpret_cast<void*>(com_android_providers_media_FuseDaemon_check_fd_access)},
Biswarup Pal93f4ec12021-02-15 13:39:36 +0000180 {"native_initialize_device_id", "(JLjava/lang/String;)V",
181 reinterpret_cast<void*>(com_android_providers_media_FuseDaemon_initialize_device_id)}};
Zim3e45d9b2019-08-19 21:14:14 +0100182} // namespace
183
Narayan Kamathde3fe172020-02-18 12:14:51 +0000184void register_android_providers_media_FuseDaemon(JavaVM* vm, JNIEnv* env) {
Zim08041a82022-01-13 15:43:38 +0000185 gFuseDaemonClass =
186 static_cast<jclass>(env->NewGlobalRef(env->FindClass(FUSE_DAEMON_CLASS_NAME)));
187 gFdAccessResultClass =
188 static_cast<jclass>(env->NewGlobalRef(env->FindClass(FD_ACCESS_RESULT_CLASS_NAME)));
Narayan Kamath88203dc2019-08-30 17:19:38 +0100189
190 if (gFuseDaemonClass == nullptr) {
Zim08041a82022-01-13 15:43:38 +0000191 LOG(FATAL) << "Unable to find class : " << FUSE_DAEMON_CLASS_NAME;
192 }
193
194 if (gFdAccessResultClass == nullptr) {
195 LOG(FATAL) << "Unable to find class : " << FD_ACCESS_RESULT_CLASS_NAME;
Narayan Kamath88203dc2019-08-30 17:19:38 +0100196 }
197
shafik8b57cd52019-09-06 10:51:29 +0100198 if (env->RegisterNatives(gFuseDaemonClass, methods, sizeof(methods) / sizeof(methods[0])) < 0) {
Narayan Kamath88203dc2019-08-30 17:19:38 +0100199 LOG(FATAL) << "Unable to register native methods";
200 }
Narayan Kamathde3fe172020-02-18 12:14:51 +0000201
Zim08041a82022-01-13 15:43:38 +0000202 gFdAccessResultCtor = env->GetMethodID(gFdAccessResultClass, "<init>", "(Ljava/lang/String;Z)V");
203 if (gFdAccessResultCtor == nullptr) {
204 LOG(FATAL) << "Unable to find ctor for FdAccessResult";
205 }
206
Narayan Kamathde3fe172020-02-18 12:14:51 +0000207 fuse::MediaProviderWrapper::OneTimeInit(vm);
Zim3e45d9b2019-08-19 21:14:14 +0100208}
209} // namespace mediaprovider