• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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