1 //! aconfig storage read api java rust interlop
2
3 use aconfig_storage_file::SipHasher13;
4 use aconfig_storage_read_api::flag_table_query::find_flag_read_context;
5 use aconfig_storage_read_api::flag_value_query::find_boolean_flag_value;
6 use aconfig_storage_read_api::package_table_query::find_package_read_context;
7 use aconfig_storage_read_api::{FlagReadContext, PackageReadContext};
8
9 use anyhow::Result;
10 use jni::objects::{JByteBuffer, JClass, JString};
11 use jni::sys::{jboolean, jint, jlong};
12 use jni::JNIEnv;
13 use std::hash::Hasher;
14
15 /// Call rust find package read context
get_package_read_context_java( env: &mut JNIEnv, file: JByteBuffer, package: JString, ) -> Result<Option<PackageReadContext>>16 fn get_package_read_context_java(
17 env: &mut JNIEnv,
18 file: JByteBuffer,
19 package: JString,
20 ) -> Result<Option<PackageReadContext>> {
21 // SAFETY:
22 // The safety here is ensured as the package name is guaranteed to be a java string
23 let package_name: String = unsafe { env.get_string_unchecked(&package)?.into() };
24 let buffer_ptr = env.get_direct_buffer_address(&file)?;
25 let buffer_size = env.get_direct_buffer_capacity(&file)?;
26 // SAFETY:
27 // The safety here is ensured as only non null MemoryMappedBuffer will be passed in,
28 // so the conversion to slice is guaranteed to be valid
29 let buffer = unsafe { std::slice::from_raw_parts(buffer_ptr, buffer_size) };
30 Ok(find_package_read_context(buffer, &package_name)?)
31 }
32
33 /// Get package read context JNI
34 #[no_mangle]
35 #[allow(unused)]
Java_android_aconfig_storage_AconfigStorageReadAPI_getPackageReadContextImpl< 'local, >( mut env: JNIEnv<'local>, class: JClass<'local>, file: JByteBuffer<'local>, package: JString<'local>, ) -> JByteBuffer<'local>36 pub extern "system" fn Java_android_aconfig_storage_AconfigStorageReadAPI_getPackageReadContextImpl<
37 'local,
38 >(
39 mut env: JNIEnv<'local>,
40 class: JClass<'local>,
41 file: JByteBuffer<'local>,
42 package: JString<'local>,
43 ) -> JByteBuffer<'local> {
44 let mut package_id = -1;
45 let mut boolean_start_index = -1;
46
47 match get_package_read_context_java(&mut env, file, package) {
48 Ok(context_opt) => {
49 if let Some(context) = context_opt {
50 package_id = context.package_id as i32;
51 boolean_start_index = context.boolean_start_index as i32;
52 }
53 }
54 Err(errmsg) => {
55 env.throw(("java/io/IOException", errmsg.to_string())).expect("failed to throw");
56 }
57 }
58
59 let mut bytes = Vec::new();
60 bytes.extend_from_slice(&package_id.to_le_bytes());
61 bytes.extend_from_slice(&boolean_start_index.to_le_bytes());
62 let (addr, len) = {
63 let buf = bytes.leak();
64 (buf.as_mut_ptr(), buf.len())
65 };
66 // SAFETY:
67 // The safety here is ensured as the content is ensured to be valid
68 unsafe { env.new_direct_byte_buffer(addr, len).expect("failed to create byte buffer") }
69 }
70
71 /// Call rust find flag read context
get_flag_read_context_java( env: &mut JNIEnv, file: JByteBuffer, package_id: jint, flag: JString, ) -> Result<Option<FlagReadContext>>72 fn get_flag_read_context_java(
73 env: &mut JNIEnv,
74 file: JByteBuffer,
75 package_id: jint,
76 flag: JString,
77 ) -> Result<Option<FlagReadContext>> {
78 // SAFETY:
79 // The safety here is ensured as the flag name is guaranteed to be a java string
80 let flag_name: String = unsafe { env.get_string_unchecked(&flag)?.into() };
81 let buffer_ptr = env.get_direct_buffer_address(&file)?;
82 let buffer_size = env.get_direct_buffer_capacity(&file)?;
83 // SAFETY:
84 // The safety here is ensured as only non null MemoryMappedBuffer will be passed in,
85 // so the conversion to slice is guaranteed to be valid
86 let buffer = unsafe { std::slice::from_raw_parts(buffer_ptr, buffer_size) };
87 Ok(find_flag_read_context(buffer, package_id as u32, &flag_name)?)
88 }
89
90 /// Get flag read context JNI
91 #[no_mangle]
92 #[allow(unused)]
Java_android_aconfig_storage_AconfigStorageReadAPI_getFlagReadContextImpl< 'local, >( mut env: JNIEnv<'local>, class: JClass<'local>, file: JByteBuffer<'local>, package_id: jint, flag: JString<'local>, ) -> JByteBuffer<'local>93 pub extern "system" fn Java_android_aconfig_storage_AconfigStorageReadAPI_getFlagReadContextImpl<
94 'local,
95 >(
96 mut env: JNIEnv<'local>,
97 class: JClass<'local>,
98 file: JByteBuffer<'local>,
99 package_id: jint,
100 flag: JString<'local>,
101 ) -> JByteBuffer<'local> {
102 let mut flag_type = -1;
103 let mut flag_index = -1;
104
105 match get_flag_read_context_java(&mut env, file, package_id, flag) {
106 Ok(context_opt) => {
107 if let Some(context) = context_opt {
108 flag_type = context.flag_type as i32;
109 flag_index = context.flag_index as i32;
110 }
111 }
112 Err(errmsg) => {
113 env.throw(("java/io/IOException", errmsg.to_string())).expect("failed to throw");
114 }
115 }
116
117 let mut bytes = Vec::new();
118 bytes.extend_from_slice(&flag_type.to_le_bytes());
119 bytes.extend_from_slice(&flag_index.to_le_bytes());
120 let (addr, len) = {
121 let buf = bytes.leak();
122 (buf.as_mut_ptr(), buf.len())
123 };
124 // SAFETY:
125 // The safety here is ensured as the content is ensured to be valid
126 unsafe { env.new_direct_byte_buffer(addr, len).expect("failed to create byte buffer") }
127 }
128
129 /// Call rust find boolean flag value
get_boolean_flag_value_java( env: &mut JNIEnv, file: JByteBuffer, flag_index: jint, ) -> Result<bool>130 fn get_boolean_flag_value_java(
131 env: &mut JNIEnv,
132 file: JByteBuffer,
133 flag_index: jint,
134 ) -> Result<bool> {
135 let buffer_ptr = env.get_direct_buffer_address(&file)?;
136 let buffer_size = env.get_direct_buffer_capacity(&file)?;
137 // SAFETY:
138 // The safety here is ensured as only non null MemoryMappedBuffer will be passed in,
139 // so the conversion to slice is guaranteed to be valid
140 let buffer = unsafe { std::slice::from_raw_parts(buffer_ptr, buffer_size) };
141 Ok(find_boolean_flag_value(buffer, flag_index as u32)?)
142 }
143
144 /// Get flag value JNI
145 #[no_mangle]
146 #[allow(unused)]
Java_android_aconfig_storage_AconfigStorageReadAPI_getBooleanFlagValue< 'local, >( mut env: JNIEnv<'local>, class: JClass<'local>, file: JByteBuffer<'local>, flag_index: jint, ) -> jboolean147 pub extern "system" fn Java_android_aconfig_storage_AconfigStorageReadAPI_getBooleanFlagValue<
148 'local,
149 >(
150 mut env: JNIEnv<'local>,
151 class: JClass<'local>,
152 file: JByteBuffer<'local>,
153 flag_index: jint,
154 ) -> jboolean {
155 match get_boolean_flag_value_java(&mut env, file, flag_index) {
156 Ok(value) => value as u8,
157 Err(errmsg) => {
158 env.throw(("java/io/IOException", errmsg.to_string())).expect("failed to throw");
159 0u8
160 }
161 }
162 }
163
164 /// Get flag value JNI
165 #[no_mangle]
166 #[allow(unused)]
Java_android_aconfig_storage_AconfigStorageReadAPI_hash<'local>( mut env: JNIEnv<'local>, class: JClass<'local>, package_name: JString<'local>, ) -> jlong167 pub extern "system" fn Java_android_aconfig_storage_AconfigStorageReadAPI_hash<'local>(
168 mut env: JNIEnv<'local>,
169 class: JClass<'local>,
170 package_name: JString<'local>,
171 ) -> jlong {
172 match siphasher13_hash(&mut env, package_name) {
173 Ok(value) => value as jlong,
174 Err(errmsg) => {
175 env.throw(("java/io/IOException", errmsg.to_string())).expect("failed to throw");
176 0i64
177 }
178 }
179 }
180
siphasher13_hash(env: &mut JNIEnv, package_name: JString) -> Result<u64>181 fn siphasher13_hash(env: &mut JNIEnv, package_name: JString) -> Result<u64> {
182 // SAFETY:
183 // The safety here is ensured as the flag name is guaranteed to be a java string
184 let flag_name: String = unsafe { env.get_string_unchecked(&package_name)?.into() };
185 let mut s = SipHasher13::new();
186 s.write(flag_name.as_bytes());
187 s.write_u8(0xff);
188 Ok(s.finish())
189 }
190