Read an unknown SoC as Qualcomm's

The generic runtime is opened only when the QNN build does not fit, and
the fit rests on ro.soc.manufacturer. A property the app cannot read, or
an Android older than 12 that has none, read as "not Qualcomm" would
put a Qualcomm device on the generic rung and off its Hexagon — what
0.22.1 had just fixed. Only a device that names another vendor is now
not Qualcomm's; the tablet reports QTI.
This commit is contained in:
2026-10-04 22:26:56 -04:00
parent 4b33754482
commit 4822991bec
+26 -7
View File
@@ -95,10 +95,12 @@ pub fn detect() -> Gpus {
#[cfg(target_os = "android")] #[cfg(target_os = "android")]
pub fn detect() -> Gpus { pub fn detect() -> Gpus {
// `ro.soc.manufacturer` exists from Android 12. Qualcomm's FastRPC // Fail-safe: only a device that names another vendor is not Qualcomm.
// library, which the Hexagon path loads anyway, is the second witness: // `ro.soc.manufacturer` exists from Android 12, and a property or file
// a Qualcomm device read as anything else would trade its NPU for the // the app cannot read reads as nothing; nothing keeps the QNN build
// generic rung. // first, as 0.22 had it, where a Qualcomm device mistaken for another
// would trade its NPU for the generic rung. Qualcomm's FastRPC library,
// which the Hexagon path loads anyway, overrules a name.
let soc = crate::probe::system_property("ro.soc.manufacturer"); let soc = crate::probe::system_property("ro.soc.manufacturer");
let fastrpc = [ let fastrpc = [
"/vendor/lib64/libcdsprpc.so", "/vendor/lib64/libcdsprpc.so",
@@ -107,13 +109,19 @@ pub fn detect() -> Gpus {
.iter() .iter()
.any(|p| std::path::Path::new(p).exists()); .any(|p| std::path::Path::new(p).exists());
Gpus { Gpus {
qualcomm: soc.eq_ignore_ascii_case("QTI") qualcomm: qualcomm_soc(&soc) || fastrpc,
|| soc.eq_ignore_ascii_case("Qualcomm")
|| fastrpc,
..Gpus::default() ..Gpus::default()
} }
} }
/// Whether `ro.soc.manufacturer` leaves the device Qualcomm's: it says so,
/// or it says nothing.
#[cfg(any(target_os = "android", test))]
fn qualcomm_soc(manufacturer: &str) -> bool {
let m = manufacturer.trim();
m.is_empty() || m.eq_ignore_ascii_case("QTI") || m.eq_ignore_ascii_case("Qualcomm")
}
#[cfg(not(any(target_os = "linux", target_os = "windows", target_os = "android")))] #[cfg(not(any(target_os = "linux", target_os = "windows", target_os = "android")))]
pub fn detect() -> Gpus { pub fn detect() -> Gpus {
Gpus::default() Gpus::default()
@@ -127,6 +135,17 @@ mod tests {
p.iter().map(|s| s.to_string()).collect() p.iter().map(|s| s.to_string()).collect()
} }
#[test]
fn only_a_named_other_vendor_is_not_qualcomm() {
assert!(qualcomm_soc("QTI"));
assert!(qualcomm_soc("Qualcomm"));
// Unreadable, or older than Android 12: the QNN build stays first.
assert!(qualcomm_soc(""));
assert!(!qualcomm_soc("Mediatek"));
assert!(!qualcomm_soc("Google"));
assert!(!qualcomm_soc("Samsung"));
}
#[test] #[test]
fn the_card_beats_the_integrated_gpu_and_both_beat_the_generic_rung() { fn the_card_beats_the_integrated_gpu_and_both_beat_the_generic_rung() {
let cpu = offers(&["CPUExecutionProvider"]); let cpu = offers(&["CPUExecutionProvider"]);