android_keyring/
methods.rs

1use jni::{
2    JNIEnv,
3    objects::{GlobalRef, JByteArray, JObject, JValue, JValueGen, ReleaseMode},
4    signature::{Primitive, ReturnType},
5};
6
7#[derive(Clone, Copy)]
8pub enum SignatureComp {
9    Class(ClassDecl),
10    Boolean,
11    Byte,
12    Char,
13    Short,
14    Int,
15    Long,
16    Float,
17    Double,
18    Void,
19    ArrayBoolean,
20    ArrayByte,
21    ArrayChar,
22    ArrayShort,
23    ArrayInt,
24    ArrayLong,
25    ArrayFloat,
26    ArrayDouble,
27}
28impl From<ClassDecl> for SignatureComp {
29    fn from(value: ClassDecl) -> Self {
30        Self::Class(value)
31    }
32}
33impl From<SignatureComp> for ReturnType {
34    fn from(value: SignatureComp) -> Self {
35        match value {
36            SignatureComp::Class(class_decl) if class_decl.0.starts_with('[') => ReturnType::Array,
37            SignatureComp::Class(_) => ReturnType::Object,
38            SignatureComp::Boolean => ReturnType::Primitive(Primitive::Boolean),
39            SignatureComp::Byte => ReturnType::Primitive(Primitive::Byte),
40            SignatureComp::Char => ReturnType::Primitive(Primitive::Char),
41            SignatureComp::Short => ReturnType::Primitive(Primitive::Short),
42            SignatureComp::Int => ReturnType::Primitive(Primitive::Int),
43            SignatureComp::Long => ReturnType::Primitive(Primitive::Long),
44            SignatureComp::Float => ReturnType::Primitive(Primitive::Float),
45            SignatureComp::Double => ReturnType::Primitive(Primitive::Double),
46            SignatureComp::Void => ReturnType::Primitive(Primitive::Void),
47            SignatureComp::ArrayBoolean => ReturnType::Array,
48            SignatureComp::ArrayByte => ReturnType::Array,
49            SignatureComp::ArrayChar => ReturnType::Array,
50            SignatureComp::ArrayShort => ReturnType::Array,
51            SignatureComp::ArrayInt => ReturnType::Array,
52            SignatureComp::ArrayLong => ReturnType::Array,
53            SignatureComp::ArrayFloat => ReturnType::Array,
54            SignatureComp::ArrayDouble => ReturnType::Array,
55        }
56    }
57}
58impl SignatureComp {
59    fn for_finding(self) -> &'static str {
60        match self {
61            SignatureComp::Class(class_decl) => class_decl.for_finding(),
62            other => other.as_str(),
63        }
64    }
65
66    fn as_str(self) -> &'static str {
67        match self {
68            SignatureComp::Class(ClassDecl(class_decl)) => class_decl,
69            SignatureComp::Boolean => "Z",
70            SignatureComp::Byte => "B",
71            SignatureComp::Char => "C",
72            SignatureComp::Short => "S",
73            SignatureComp::Int => "I",
74            SignatureComp::Long => "J",
75            SignatureComp::Float => "F",
76            SignatureComp::Double => "D",
77            SignatureComp::Void => "V",
78            SignatureComp::ArrayBoolean => "[Z",
79            SignatureComp::ArrayByte => "[B",
80            SignatureComp::ArrayChar => "[C",
81            SignatureComp::ArrayShort => "[S",
82            SignatureComp::ArrayInt => "[I",
83            SignatureComp::ArrayLong => "[J",
84            SignatureComp::ArrayFloat => "[F",
85            SignatureComp::ArrayDouble => "[D",
86        }
87    }
88}
89
90#[derive(Clone, Copy)]
91pub struct ClassDecl(pub &'static str);
92impl ClassDecl {
93    fn for_finding(self) -> &'static str {
94        if !self.0.is_empty() && &self.0[0..1] == "[" {
95            return self.0;
96        }
97
98        &self.0[..(self.0.len() - 1)][1..]
99    }
100}
101
102pub trait Method {
103    type Param: AsParam;
104    type Return: FromValue;
105
106    const NAME: &str;
107
108    fn call(self_: &JObject, env: &mut JNIEnv, params: Self::Param) -> JResult<Self::Return> {
109        let signature = make_signature(&Self::Param::signature(), Self::Return::signature());
110        let param = params.as_param(env)?;
111        let param = borrow_params(&param);
112        let r = env.call_method(self_, Self::NAME, &signature, param.as_slice())?;
113
114        match r {
115            JValueGen::Object(obj) if obj.is_null() => Ok(FromValue::from_null()?),
116            JValueGen::Object(obj) => Ok(FromValue::from_object(env.new_global_ref(obj)?, env)?),
117            JValueGen::Byte(value) => Ok(FromValue::from_value(JValueGen::Byte(value))?),
118            JValueGen::Char(value) => Ok(FromValue::from_value(JValueGen::Char(value))?),
119            JValueGen::Short(value) => Ok(FromValue::from_value(JValueGen::Short(value))?),
120            JValueGen::Int(value) => Ok(FromValue::from_value(JValueGen::Int(value))?),
121            JValueGen::Long(value) => Ok(FromValue::from_value(JValueGen::Long(value))?),
122            JValueGen::Bool(value) => Ok(FromValue::from_value(JValueGen::Bool(value))?),
123            JValueGen::Float(value) => Ok(FromValue::from_value(JValueGen::Float(value))?),
124            JValueGen::Double(value) => Ok(FromValue::from_value(JValueGen::Double(value))?),
125            JValueGen::Void => Ok(FromValue::from_value(JValueGen::Void)?),
126        }
127    }
128}
129
130pub trait StaticMethod {
131    type Param: AsParam;
132    type Return: FromValue;
133
134    const NAME: &str;
135
136    fn call(self_: ClassDecl, env: &mut JNIEnv, params: Self::Param) -> JResult<Self::Return> {
137        let signature = make_signature(&Self::Param::signature(), Self::Return::signature());
138        let param = params.as_param(env)?;
139        let param = borrow_params(&param);
140        let r = env.call_static_method(
141            self_.for_finding(),
142            Self::NAME,
143            &signature,
144            param.as_slice(),
145        )?;
146
147        match r {
148            JValueGen::Object(obj) if obj.is_null() => Ok(FromValue::from_null()?),
149            JValueGen::Object(obj) => Ok(FromValue::from_object(env.new_global_ref(obj)?, env)?),
150            JValueGen::Byte(value) => Ok(FromValue::from_value(JValueGen::Byte(value))?),
151            JValueGen::Char(value) => Ok(FromValue::from_value(JValueGen::Char(value))?),
152            JValueGen::Short(value) => Ok(FromValue::from_value(JValueGen::Short(value))?),
153            JValueGen::Int(value) => Ok(FromValue::from_value(JValueGen::Int(value))?),
154            JValueGen::Long(value) => Ok(FromValue::from_value(JValueGen::Long(value))?),
155            JValueGen::Bool(value) => Ok(FromValue::from_value(JValueGen::Bool(value))?),
156            JValueGen::Float(value) => Ok(FromValue::from_value(JValueGen::Float(value))?),
157            JValueGen::Double(value) => Ok(FromValue::from_value(JValueGen::Double(value))?),
158            JValueGen::Void => Ok(FromValue::from_value(JValueGen::Void)?),
159        }
160    }
161}
162
163pub trait Constructible {
164    type Param: AsParam;
165    type Return: FromValue;
166
167    fn call_new(self_: ClassDecl, env: &mut JNIEnv, params: Self::Param) -> JResult<Self::Return> {
168        let signature = make_signature(&Self::Param::signature(), <() as FromValue>::signature());
169        let param = params.as_param(env)?;
170        let param = borrow_params(&param);
171        let obj = env.new_object(self_.for_finding(), &signature, param.as_slice())?;
172
173        FromValue::from_object(env.new_global_ref(obj)?, env)
174    }
175}
176
177pub trait AsParam {
178    fn signature() -> Vec<SignatureComp>;
179    fn as_param<'a>(&self, env: &mut JNIEnv<'a>) -> JResult<Vec<JValueGen<JObject<'a>>>>;
180}
181impl<T1> AsParam for T1
182where
183    T1: ToValue,
184{
185    fn signature() -> Vec<SignatureComp> {
186        vec![T1::signature()]
187    }
188
189    fn as_param<'a>(&self, env: &mut JNIEnv<'a>) -> JResult<Vec<JValueGen<JObject<'a>>>> {
190        Ok(vec![self.to_value(env)?])
191    }
192}
193impl<T1, T2> AsParam for (T1, T2)
194where
195    T1: ToValue,
196    T2: ToValue,
197{
198    fn signature() -> Vec<SignatureComp> {
199        vec![T1::signature(), T2::signature()]
200    }
201
202    fn as_param<'a>(&self, env: &mut JNIEnv<'a>) -> JResult<Vec<JValueGen<JObject<'a>>>> {
203        Ok(vec![self.0.to_value(env)?, self.1.to_value(env)?])
204    }
205}
206impl<T1, T2, T3> AsParam for (T1, T2, T3)
207where
208    T1: ToValue,
209    T2: ToValue,
210    T3: ToValue,
211{
212    fn signature() -> Vec<SignatureComp> {
213        vec![T1::signature(), T2::signature(), T3::signature()]
214    }
215
216    fn as_param<'a>(&self, env: &mut JNIEnv<'a>) -> JResult<Vec<JValueGen<JObject<'a>>>> {
217        Ok(vec![
218            self.0.to_value(env)?,
219            self.1.to_value(env)?,
220            self.2.to_value(env)?,
221        ])
222    }
223}
224
225pub struct NoParam;
226impl AsParam for NoParam {
227    fn signature() -> Vec<SignatureComp> {
228        vec![]
229    }
230
231    fn as_param<'a>(&self, _env: &mut JNIEnv<'a>) -> JResult<Vec<JValueGen<JObject<'a>>>> {
232        Ok(vec![])
233    }
234}
235
236pub trait ToValue: Sized {
237    fn signature() -> SignatureComp;
238    fn to_value<'a>(&self, env: &mut JNIEnv<'a>) -> JResult<JValueGen<JObject<'a>>>;
239}
240impl<T: ToValue> ToValue for &T {
241    fn signature() -> SignatureComp {
242        T::signature()
243    }
244
245    fn to_value<'a>(&self, env: &mut JNIEnv<'a>) -> JResult<JValueGen<JObject<'a>>> {
246        T::to_value(self, env)
247    }
248}
249impl<T: ToValue> ToValue for Option<T> {
250    fn signature() -> SignatureComp {
251        T::signature()
252    }
253
254    fn to_value<'a>(&self, env: &mut JNIEnv<'a>) -> JResult<JValueGen<JObject<'a>>> {
255        Ok(match self {
256            Some(self_) => self_.to_value(env)?,
257            None => JObject::null().into(),
258        })
259    }
260}
261impl ToValue for &str {
262    fn signature() -> SignatureComp {
263        <String as FromValue>::signature()
264    }
265
266    fn to_value<'a>(&self, env: &mut JNIEnv<'a>) -> JResult<JValueGen<JObject<'a>>> {
267        Ok(JValueGen::Object(env.new_string(self)?.into()))
268    }
269}
270impl ToValue for &[&str] {
271    fn signature() -> SignatureComp {
272        ClassDecl("[Ljava/lang/String;").into()
273    }
274
275    fn to_value<'a>(&self, env: &mut JNIEnv<'a>) -> JResult<JValueGen<JObject<'a>>> {
276        let array = env.new_object_array(
277            self.len() as i32,
278            <&str as ToValue>::signature().for_finding(),
279            JObject::null(),
280        )?;
281
282        for (index, value) in self.iter().enumerate() {
283            env.set_object_array_element(&array, index as i32, env.new_string(*value)?)?;
284        }
285
286        let array: JObject = array.into();
287        Ok(array.into())
288    }
289}
290impl ToValue for &[u8] {
291    fn signature() -> SignatureComp {
292        SignatureComp::ArrayByte
293    }
294
295    fn to_value<'a>(&self, env: &mut JNIEnv<'a>) -> JResult<JValueGen<JObject<'a>>> {
296        let bytes: JObject = env.byte_array_from_slice(self)?.into();
297        Ok(bytes.into())
298    }
299}
300impl ToValue for Vec<u16> {
301    fn signature() -> SignatureComp {
302        SignatureComp::ArrayChar
303    }
304
305    fn to_value<'a>(&self, env: &mut JNIEnv<'a>) -> JResult<JValueGen<JObject<'a>>> {
306        let chars = env.new_char_array(self.len() as i32)?;
307        unsafe {
308            let mut chars_write = env.get_array_elements(&chars, ReleaseMode::CopyBack)?;
309            chars_write.copy_from_slice(self);
310        }
311        let chars: JObject = chars.into();
312        Ok(chars.into())
313    }
314}
315impl ToValue for i32 {
316    fn signature() -> SignatureComp {
317        SignatureComp::Int
318    }
319
320    fn to_value<'a>(&self, _env: &mut JNIEnv<'a>) -> JResult<JValueGen<JObject<'a>>> {
321        Ok((*self).into())
322    }
323}
324impl ToValue for bool {
325    fn signature() -> SignatureComp {
326        SignatureComp::Boolean
327    }
328
329    fn to_value<'a>(&self, _env: &mut JNIEnv<'a>) -> JResult<JValueGen<JObject<'a>>> {
330        Ok((*self).into())
331    }
332}
333
334pub trait FromValue: Sized {
335    fn signature() -> SignatureComp;
336
337    fn from_object(value: GlobalRef, env: &mut JNIEnv) -> JResult<Self> {
338        let _ = (value, env);
339        Err(jni::errors::Error::WrongJValueType("primitive", "object"))
340    }
341
342    fn from_value(value: JValue) -> JResult<Self> {
343        Err(jni::errors::Error::WrongJValueType(
344            "object",
345            value.type_name(),
346        ))
347    }
348
349    fn from_null() -> JResult<Self> {
350        Err(jni::errors::Error::WrongJValueType("object", "null"))
351    }
352}
353impl<T: FromValue> FromValue for Option<T> {
354    fn signature() -> SignatureComp {
355        T::signature()
356    }
357
358    fn from_null() -> JResult<Self> {
359        Ok(Self::None)
360    }
361
362    fn from_object(value: GlobalRef, env: &mut JNIEnv) -> JResult<Self> {
363        Ok(Some(T::from_object(value, env)?))
364    }
365
366    fn from_value(value: JValue) -> JResult<Self> {
367        Ok(Some(T::from_value(value)?))
368    }
369}
370impl FromValue for () {
371    fn signature() -> SignatureComp {
372        SignatureComp::Void
373    }
374
375    fn from_value(value: JValue) -> JResult<Self> {
376        value.v()
377    }
378
379    fn from_null() -> JResult<Self> {
380        Ok(())
381    }
382}
383impl FromValue for bool {
384    fn signature() -> SignatureComp {
385        SignatureComp::Boolean
386    }
387
388    fn from_value(value: JValue) -> JResult<Self> {
389        value.z()
390    }
391}
392impl FromValue for String {
393    fn signature() -> SignatureComp {
394        ClassDecl("Ljava/lang/String;").into()
395    }
396
397    fn from_object(value: GlobalRef, env: &mut JNIEnv) -> JResult<Self> {
398        let string = env.get_string((&value as &JObject).into())?;
399        Ok(string.to_string_lossy().into_owned())
400    }
401}
402impl FromValue for Vec<u8> {
403    fn signature() -> SignatureComp {
404        SignatureComp::ArrayByte
405    }
406
407    fn from_object(value: GlobalRef, env: &mut JNIEnv) -> JResult<Self> {
408        let value: &JByteArray = value.as_obj().into();
409        let len = env.get_array_length(value)? as usize;
410        let mut buf = vec![0; len];
411        env.get_byte_array_region(value, 0, &mut buf)?;
412
413        Ok(buf.into_iter().map(|x| x as u8).collect())
414    }
415}
416
417fn make_signature(params: &[SignatureComp], result: SignatureComp) -> String {
418    use std::fmt::Write;
419    let mut w = String::new();
420    write!(w, "(").unwrap();
421    for param in params {
422        write!(w, "{}", param.as_str()).unwrap();
423    }
424    write!(w, "){}", result.as_str()).unwrap();
425    w
426}
427
428fn borrow_params<'a, 'b>(
429    params: &'a Vec<JValueGen<JObject<'b>>>,
430) -> Vec<JValueGen<&'a JObject<'b>>> {
431    params
432        .iter()
433        .map(|value| match value {
434            JValueGen::Object(value) => JValueGen::Object(value),
435            JValueGen::Byte(value) => JValueGen::Byte(*value),
436            JValueGen::Char(value) => JValueGen::Char(*value),
437            JValueGen::Short(value) => JValueGen::Short(*value),
438            JValueGen::Int(value) => JValueGen::Int(*value),
439            JValueGen::Long(value) => JValueGen::Long(*value),
440            JValueGen::Bool(value) => JValueGen::Bool(*value),
441            JValueGen::Float(value) => JValueGen::Float(*value),
442            JValueGen::Double(value) => JValueGen::Double(*value),
443            JValueGen::Void => JValueGen::Void,
444        })
445        .collect()
446}
447
448pub type JResult<T> = Result<T, jni::errors::Error>;