• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2016 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 specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #define LOG_TAG "FuseAppLoopJNI"
18 #define LOG_NDEBUG 0
19 
20 #include <stdlib.h>
21 #include <sys/stat.h>
22 
23 #include <map>
24 #include <memory>
25 
26 #include <android_runtime/Log.h>
27 #include <android-base/logging.h>
28 #include <android-base/unique_fd.h>
29 #include <jni.h>
30 #include <libappfuse/FuseAppLoop.h>
31 #include <nativehelper/ScopedLocalRef.h>
32 #include <nativehelper/ScopedPrimitiveArray.h>
33 
34 #include "core_jni_helpers.h"
35 
36 namespace android {
37 namespace {
38 constexpr const char* CLASS_NAME = "com/android/internal/os/FuseAppLoop";
39 
40 jclass gFuseAppLoopClass;
41 jmethodID gOnCommandMethod;
42 jmethodID gOnOpenMethod;
43 
44 class Callback : public fuse::FuseAppLoopCallback {
45 private:
46     typedef ScopedLocalRef<jbyteArray> LocalBytes;
47     JNIEnv* const mEnv;
48     jobject const mSelf;
49     std::map<uint64_t, std::unique_ptr<LocalBytes>> mBuffers;
50 
51 public:
Callback(JNIEnv * env,jobject self)52     Callback(JNIEnv* env, jobject self) :
53         mEnv(env), mSelf(self) {}
54 
OnLookup(uint64_t unique,uint64_t inode)55     void OnLookup(uint64_t unique, uint64_t inode) override {
56         CallOnCommand(FUSE_LOOKUP, unique, inode, 0, 0, nullptr);
57     }
58 
OnGetAttr(uint64_t unique,uint64_t inode)59     void OnGetAttr(uint64_t unique, uint64_t inode) override {
60         CallOnCommand(FUSE_GETATTR, unique, inode, 0, 0, nullptr);
61     }
62 
OnOpen(uint64_t unique,uint64_t inode)63     void OnOpen(uint64_t unique, uint64_t inode) override {
64         const jbyteArray buffer = static_cast<jbyteArray>(mEnv->CallObjectMethod(
65                 mSelf, gOnOpenMethod, unique, inode));
66         CHECK(!mEnv->ExceptionCheck());
67         if (buffer == nullptr) {
68             return;
69         }
70 
71         mBuffers.insert(std::make_pair(inode, std::unique_ptr<LocalBytes>(
72                 new LocalBytes(mEnv, buffer))));
73     }
74 
OnFsync(uint64_t unique,uint64_t inode)75     void OnFsync(uint64_t unique, uint64_t inode) override {
76         CallOnCommand(FUSE_FSYNC, unique, inode, 0, 0, nullptr);
77     }
78 
OnRelease(uint64_t unique,uint64_t inode)79     void OnRelease(uint64_t unique, uint64_t inode) override {
80         mBuffers.erase(inode);
81         CallOnCommand(FUSE_RELEASE, unique, inode, 0, 0, nullptr);
82     }
83 
OnRead(uint64_t unique,uint64_t inode,uint64_t offset,uint32_t size)84     void OnRead(uint64_t unique, uint64_t inode, uint64_t offset, uint32_t size) override {
85         CHECK_LE(size, static_cast<uint32_t>(fuse::kFuseMaxRead));
86 
87         auto it = mBuffers.find(inode);
88         CHECK(it != mBuffers.end());
89 
90         CallOnCommand(FUSE_READ, unique, inode, offset, size, it->second->get());
91     }
92 
OnWrite(uint64_t unique,uint64_t inode,uint64_t offset,uint32_t size,const void * buffer)93     void OnWrite(uint64_t unique, uint64_t inode, uint64_t offset, uint32_t size,
94             const void* buffer) override {
95         CHECK_LE(size, static_cast<uint32_t>(fuse::kFuseMaxWrite));
96 
97         auto it = mBuffers.find(inode);
98         CHECK(it != mBuffers.end());
99 
100         jbyteArray const javaBuffer = it->second->get();
101 
102         mEnv->SetByteArrayRegion(javaBuffer, 0, size, static_cast<const jbyte*>(buffer));
103         CHECK(!mEnv->ExceptionCheck());
104 
105         CallOnCommand(FUSE_WRITE, unique, inode, offset, size, javaBuffer);
106     }
107 
108 private:
109     // Helper function to make sure we invoke CallVoidMethod with correct size of integer arguments.
CallOnCommand(jint command,jlong unique,jlong inode,jlong offset,jint size,jobject bytes)110     void CallOnCommand(jint command, jlong unique, jlong inode, jlong offset, jint size,
111                        jobject bytes) {
112         mEnv->CallVoidMethod(mSelf, gOnCommandMethod, command, unique, inode, offset, size, bytes);
113         CHECK(!mEnv->ExceptionCheck());
114     }
115 };
116 
com_android_internal_os_FuseAppLoop_new(JNIEnv * env,jobject self,jint jfd)117 jlong com_android_internal_os_FuseAppLoop_new(JNIEnv* env, jobject self, jint jfd) {
118     return reinterpret_cast<jlong>(new fuse::FuseAppLoop(base::unique_fd(jfd)));
119 }
120 
com_android_internal_os_FuseAppLoop_delete(JNIEnv * env,jobject self,jlong ptr)121 void com_android_internal_os_FuseAppLoop_delete(JNIEnv* env, jobject self, jlong ptr) {
122     delete reinterpret_cast<fuse::FuseAppLoop*>(ptr);
123 }
124 
com_android_internal_os_FuseAppLoop_start(JNIEnv * env,jobject self,jlong ptr)125 void com_android_internal_os_FuseAppLoop_start(JNIEnv* env, jobject self, jlong ptr) {
126     Callback callback(env, self);
127     reinterpret_cast<fuse::FuseAppLoop*>(ptr)->Start(&callback);
128 }
129 
com_android_internal_os_FuseAppLoop_replySimple(JNIEnv * env,jobject self,jlong ptr,jlong unique,jint result)130 void com_android_internal_os_FuseAppLoop_replySimple(
131         JNIEnv* env, jobject self, jlong ptr, jlong unique, jint result) {
132     if (!reinterpret_cast<fuse::FuseAppLoop*>(ptr)->ReplySimple(unique, result)) {
133         reinterpret_cast<fuse::FuseAppLoop*>(ptr)->Break();
134     }
135 }
136 
com_android_internal_os_FuseAppLoop_replyOpen(JNIEnv * env,jobject self,jlong ptr,jlong unique,jlong fh)137 void com_android_internal_os_FuseAppLoop_replyOpen(
138         JNIEnv* env, jobject self, jlong ptr, jlong unique, jlong fh) {
139     if (!reinterpret_cast<fuse::FuseAppLoop*>(ptr)->ReplyOpen(unique, fh)) {
140         reinterpret_cast<fuse::FuseAppLoop*>(ptr)->Break();
141     }
142 }
143 
com_android_internal_os_FuseAppLoop_replyLookup(JNIEnv * env,jobject self,jlong ptr,jlong unique,jlong inode,jlong size)144 void com_android_internal_os_FuseAppLoop_replyLookup(
145         JNIEnv* env, jobject self, jlong ptr, jlong unique, jlong inode, jlong size) {
146     if (!reinterpret_cast<fuse::FuseAppLoop*>(ptr)->ReplyLookup(unique, inode, size)) {
147         reinterpret_cast<fuse::FuseAppLoop*>(ptr)->Break();
148     }
149 }
150 
com_android_internal_os_FuseAppLoop_replyGetAttr(JNIEnv * env,jobject self,jlong ptr,jlong unique,jlong inode,jlong size)151 void com_android_internal_os_FuseAppLoop_replyGetAttr(
152         JNIEnv* env, jobject self, jlong ptr, jlong unique, jlong inode, jlong size) {
153     if (!reinterpret_cast<fuse::FuseAppLoop*>(ptr)->ReplyGetAttr(
154             unique, inode, size, S_IFREG | 0777)) {
155         reinterpret_cast<fuse::FuseAppLoop*>(ptr)->Break();
156     }
157 }
158 
com_android_internal_os_FuseAppLoop_replyWrite(JNIEnv * env,jobject self,jlong ptr,jlong unique,jint size)159 void com_android_internal_os_FuseAppLoop_replyWrite(
160         JNIEnv* env, jobject self, jlong ptr, jlong unique, jint size) {
161     if (!reinterpret_cast<fuse::FuseAppLoop*>(ptr)->ReplyWrite(unique, size)) {
162         reinterpret_cast<fuse::FuseAppLoop*>(ptr)->Break();
163     }
164 }
165 
com_android_internal_os_FuseAppLoop_replyRead(JNIEnv * env,jobject self,jlong ptr,jlong unique,jint size,jbyteArray data)166 void com_android_internal_os_FuseAppLoop_replyRead(
167         JNIEnv* env, jobject self, jlong ptr, jlong unique, jint size, jbyteArray data) {
168     ScopedByteArrayRO array(env, data);
169     CHECK(size >= 0);
170     CHECK(static_cast<size_t>(size) < array.size());
171     if (!reinterpret_cast<fuse::FuseAppLoop*>(ptr)->ReplyRead(unique, size, array.get())) {
172         reinterpret_cast<fuse::FuseAppLoop*>(ptr)->Break();
173     }
174 }
175 
176 const JNINativeMethod methods[] = {
177     {
178         "native_new",
179         "(I)J",
180         reinterpret_cast<void*>(com_android_internal_os_FuseAppLoop_new)
181     },
182     {
183         "native_delete",
184         "(J)V",
185         reinterpret_cast<void*>(com_android_internal_os_FuseAppLoop_delete)
186     },
187     {
188         "native_start",
189         "(J)V",
190         reinterpret_cast<void*>(com_android_internal_os_FuseAppLoop_start)
191     },
192     {
193         "native_replySimple",
194         "(JJI)V",
195         reinterpret_cast<void*>(com_android_internal_os_FuseAppLoop_replySimple)
196     },
197     {
198         "native_replyOpen",
199         "(JJJ)V",
200         reinterpret_cast<void*>(com_android_internal_os_FuseAppLoop_replyOpen)
201     },
202     {
203         "native_replyLookup",
204         "(JJJJ)V",
205         reinterpret_cast<void*>(com_android_internal_os_FuseAppLoop_replyLookup)
206     },
207     {
208         "native_replyGetAttr",
209         "(JJJJ)V",
210         reinterpret_cast<void*>(com_android_internal_os_FuseAppLoop_replyGetAttr)
211     },
212     {
213         "native_replyRead",
214         "(JJI[B)V",
215         reinterpret_cast<void*>(com_android_internal_os_FuseAppLoop_replyRead)
216     },
217     {
218         "native_replyWrite",
219         "(JJI)V",
220         reinterpret_cast<void*>(com_android_internal_os_FuseAppLoop_replyWrite)
221     },
222 };
223 }  // namespace
224 
register_com_android_internal_os_FuseAppLoop(JNIEnv * env)225 int register_com_android_internal_os_FuseAppLoop(JNIEnv* env) {
226     gFuseAppLoopClass = MakeGlobalRefOrDie(env, FindClassOrDie(env, CLASS_NAME));
227     gOnCommandMethod = GetMethodIDOrDie(env, gFuseAppLoopClass, "onCommand", "(IJJJI[B)V");
228     gOnOpenMethod = GetMethodIDOrDie(env, gFuseAppLoopClass, "onOpen", "(JJ)[B");
229     RegisterMethodsOrDie(env, CLASS_NAME, methods, NELEM(methods));
230     return 0;
231 }
232 }  // namespace android
233