Skip to content

Commit c6afcd8

Browse files
committed
initial commit
0 parents  commit c6afcd8

File tree

7 files changed

+310
-0
lines changed

7 files changed

+310
-0
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
/target

Cargo.lock

Lines changed: 95 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
[package]
2+
name = "aosp-missing-blobs"
3+
version = "0.1.0"
4+
authors = ["Josh Choo <dev@joshuous.com>"]
5+
edition = "2018"
6+
description = """
7+
aosp-missing-blobs is a nifty tool to identify required blobs (.so) that are missing from AOSP ROM builds,
8+
and to show which existing blobs rely on them. This will be particularly useful for ROM developers who want
9+
to ensure that they have not missed out any required proprietary OEM blobs.
10+
"""
11+
license = "MIT"
12+
homepage = "https://github.com/joshuous/aosp-missing-blobs"
13+
repository = "https://github.com/joshuous/aosp-missing-blobs"
14+
15+
[dependencies]
16+
goblin = "0.4"

LICENSE

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
MIT License
2+
3+
Copyright (c) Josh Choo
4+
5+
Permission is hereby granted, free of charge, to any person obtaining a copy
6+
of this software and associated documentation files (the "Software"), to deal
7+
in the Software without restriction, including without limitation the rights
8+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9+
copies of the Software, and to permit persons to whom the Software is
10+
furnished to do so, subject to the following conditions:
11+
12+
The above copyright notice and this permission notice shall be included in all
13+
copies or substantial portions of the Software.
14+
15+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21+
SOFTWARE.

README.md

Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
1+
## aosp-missing-blobs
2+
3+
aosp-missing-blobs is a nifty tool to identify required blobs (.so) that are missing from AOSP ROM builds,
4+
and to show which existing blobs rely on them. This will be particularly useful for ROM developers who
5+
want to ensure that they have not missed out any required proprietary OEM blobs.
6+
7+
### Concept
8+
9+
Blobs (.so) and compiled binaries in Android need other blobs to work. It is possible to identify the
10+
dependencies for each blob by inspecting their ELF information:
11+
12+
```
13+
$ readelf -d <name_of_blob.so> | grep "\(NEEDED\)" | sed -r "s/.*\[(.*)\]/\1/"
14+
```
15+
16+
Example (finding the dependencies of `libqti_performance.so`):
17+
18+
```
19+
$ readelf -d libqti_performance.so | grep "\(NEEDED\)" | sed -r "s/.*\[(.*)\]/\1/"
20+
libnativehelper.so
21+
liblog.so
22+
libcutils.so
23+
libutils.so
24+
libbase.so
25+
vendor.qti.hardware.iop@2.0.so
26+
libhidlbase.so
27+
libhidltransport.so
28+
libqti-perfd-client_system.so
29+
libhwui.so
30+
libc++.so
31+
libc.so
32+
libm.so
33+
libdl.so
34+
```
35+
36+
From the example, we can see that `libqti_performance.so` depends on `libqti-perfd-client_system.so`
37+
and `vendor.qti.hardware.iop@2.0.so`.
38+
39+
aosp-missing-blobs uses this idea to identify all the dependencies of a given list of blobs, and to
40+
check whether any of these dependencies are not present.
41+
42+
### Building
43+
44+
aosp-missing-blobs is written in Rust, hence you'll need [Rust to be installed](https://www.rust-lang.org) to build the project.
45+
46+
In the root directory of the repo, execute:
47+
48+
```
49+
$ git clone https://github.com/joshuous/aosp-missing-blobs
50+
$ cd aosp-missing-blobs
51+
$ cargo build --release
52+
53+
$ ./target/release/aosp-missing-blobs
54+
```
55+
56+
A runnable `aosp-missing-blobs` binary will be produced.
57+
58+
### Usage
59+
60+
This program takes as arguments a **list of directories** that contain compiled binaries and blobs (.so).
61+
62+
```
63+
$ aosp-missing-blobs <blob directory1> <blob directory2> <blob directory3> <blob directoryN>
64+
```
65+
66+
#### Example
67+
68+
Assuming you have extracted the ROM's system.img and vendor.img to `~/system` and `~/vendor`, respectively, run the following:
69+
70+
```
71+
$ aosp-missing-blobs ~/system/lib ~/vendor/lib
72+
```
73+
74+
The program does the following:
75+
76+
1. Search `~/system/lib` and `~/vendor/lib` directories for blobs.
77+
2. Identify dependencies of each blob found.
78+
3. Checks if required dependencies exist in `~/system/lib` and `~/vendor/lib`.
79+
4. Output a list of missing dependencies and existing blobs that need them.
80+
81+
Depending on how wide your search scope is, the program may flag out missing dependencies 'incorrectly'.
82+
Some dependencies may exist in other directories besides what the examples have shown.
83+
Other directories with blobs include the following:
84+
85+
- /system/bin
86+
- /system/lib[64]
87+
- /system/lib[64]/vndk-28
88+
- /system/lib[64]/vndk-sp-28
89+
- /vendor/bin
90+
- /vendor/lib[64]
91+
- /vendor/lib[64]/vndk
92+
- Etc.
93+
94+
Take note that the more directories you specify as arguments, the longer the program will run for!
95+
96+
### Downloads
97+
98+
Binary downloads can be found in the [Releases](https://github.com/joshuous/AospMissingBlobs/releases).

src/lib.rs

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
use goblin::{self, Object};
2+
use std::collections::HashMap;
3+
use std::path::Path;
4+
use std::{collections::HashSet, fs};
5+
6+
pub fn run(paths: &[String]) -> goblin::error::Result<()> {
7+
let mut dependencies: HashMap<String, Vec<String>> = HashMap::new();
8+
let mut present: HashSet<String> = HashSet::new();
9+
10+
let dirs = paths
11+
.iter()
12+
.map(Path::new)
13+
.filter(|path| path.is_dir())
14+
.collect::<Vec<_>>();
15+
16+
for dir in dirs.iter() {
17+
for entry in fs::read_dir(dir)? {
18+
let path = entry?.path();
19+
20+
let filename = path
21+
.file_name()
22+
.expect("Could not get file name.")
23+
.to_str()
24+
.expect("Could not convert to string.")
25+
.to_string();
26+
27+
present.insert(filename.clone());
28+
29+
if let Some(ext) = path.extension() {
30+
if ext != "so" {
31+
continue;
32+
}
33+
} else {
34+
continue;
35+
}
36+
37+
let buffer = fs::read(&path)?;
38+
let obj = goblin::Object::parse(&buffer);
39+
40+
if let Ok(Object::Elf(elf)) = obj {
41+
for dep_str in elf.libraries {
42+
let dep = dep_str.to_string();
43+
match dependencies.get_mut(&dep) {
44+
Some(dependants) => {
45+
dependants.push(filename.clone());
46+
}
47+
None => {
48+
dependencies.insert(dep, vec![filename.clone()]);
49+
}
50+
}
51+
}
52+
}
53+
}
54+
}
55+
56+
let mut missing: Vec<String> = vec![];
57+
58+
for (dep, _) in &dependencies {
59+
if !present.contains(dep) {
60+
missing.push(dep.to_string());
61+
}
62+
}
63+
64+
for m in missing {
65+
println!("{} required by: {}", m, dependencies[&m].join("; "));
66+
}
67+
68+
Ok(())
69+
}

src/main.rs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
use std::env;
2+
3+
use aosp_missing_blobs::run;
4+
5+
fn main() {
6+
let args: Vec<String> = env::args().collect();
7+
let paths = &args[1..];
8+
9+
run(&paths).expect("An error occurred.");
10+
}

0 commit comments

Comments
 (0)