Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@ jobs:
uses: actions/upload-artifact@v4
with:
name: layers-${{ github.run_id }}
path: build-android/libs/lib/**/*
path: build-android/install/**/*
if-no-files-found: 'error'

macos:
Expand Down
2 changes: 1 addition & 1 deletion BUILD.md
Original file line number Diff line number Diff line change
Expand Up @@ -236,7 +236,7 @@ https://en.wikipedia.org/wiki/Apk_(file_format)#Package_contents

Alternatively users can also use `scripts/android.py` to build the binaries.

Note: `scripts/android.py` will place the binaries in the `build-android/libs` directory.
Note: `scripts/android.py` will place the binaries in the `build-android/install` directory.

```sh
# Build release binary for arm64-v8a
Expand Down
4 changes: 4 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,10 @@ if(BUILD_APIDUMP OR BUILD_MONITOR OR BUILD_SCREENSHOT OR BUILD_CPUTIMING)
add_subdirectory(layersvt)
endif()

if(ANDROID)
add_subdirectory(agi_launch_producer)
endif()

if(BUILD_LAYERMGR)
if(NOT Qt6_FOUND)
message("WARNING: Vulkan Configurator will be excluded from the build because Qt6 was not found. Please add Qt6 into the PATH environment variable")
Expand Down
12 changes: 12 additions & 0 deletions agi_launch_producer/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
cmake_minimum_required(VERSION 3.22.1)
project(agi_launch_producer LANGUAGES CXX)

if(NOT ANDROID)
return()
endif()

add_executable(agi_launch_producer main.cpp)

target_link_libraries(agi_launch_producer PRIVATE log)

install(TARGETS agi_launch_producer DESTINATION ${CMAKE_INSTALL_BINDIR})
125 changes: 125 additions & 0 deletions agi_launch_producer/main.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
/*
* Copyright (C) 2026 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

#include <android/log.h>
#include <dlfcn.h>
#include <fcntl.h>
#include <stdio.h>
#include <string.h>
#include <sys/system_properties.h>
#include <unistd.h>

#include <string>

#define _LOG(lvl, name, msg, ...) \
do { \
fprintf(stderr, name ": " msg "\n", ##__VA_ARGS__); \
__android_log_print(lvl, "AGI", msg, ##__VA_ARGS__); \
} while (false)

#define LOG_ERR(msg, ...) _LOG(ANDROID_LOG_ERROR, "E", msg, ##__VA_ARGS__)
#define LOG_WARN(msg, ...) _LOG(ANDROID_LOG_WARN, "W", msg, ##__VA_ARGS__)
#define LOG_INFO(msg, ...) _LOG(ANDROID_LOG_INFO, "I", msg, ##__VA_ARGS__)

#define NELEM(x) (sizeof(x) / sizeof(x[0]))

typedef void (*FN_PTR)(void);

const char* kProducerPaths[] = {
"libgpudataproducer.so",
};
const char* kPidFileName = "/data/local/tmp/agi_launch_producer.pid";

FN_PTR loadLibrary(const char* lib) {
char* error;

LOG_INFO("Trying %s", lib);
void* handle = dlopen(lib, RTLD_GLOBAL);
if ((error = dlerror()) != nullptr || handle == nullptr) {
LOG_WARN("Error loading lib: %s", error);
return nullptr;
}

FN_PTR startFunc = (FN_PTR)dlsym(handle, "start");
if ((error = dlerror()) != nullptr) {
LOG_ERR("Error looking for start symbol: %s", error);
dlclose(handle);
return nullptr;
}
return startFunc;
}

// If a previous producer has died without cleaning up its pidfile,
// here we kill a PID that may be related to another process.
// This is a risk we take, it would be rare for a previous PID to be reused,
// and in the worst case we kill a non-critical application as core services
// are not killable that easily.
void killExistingProcess() {
int fd = open(kPidFileName, O_RDONLY);
if (fd == -1) {
return;
}
char pidString[10];
if (read(fd, pidString, 10) > 0) {
int pid = -1;
sscanf(pidString, "%d", &pid);
if (pid > 0) {
kill(pid, SIGINT);
}
}
close(fd);
}

bool writeToPidFile() {
killExistingProcess();
int fd = open(kPidFileName, O_CREAT | O_WRONLY | O_TRUNC,
S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH);
if (fd == -1) {
return false;
}
pid_t pid = getpid();
char pidString[10];
sprintf(pidString, "%d", pid);
write(fd, pidString, strlen(pidString));
close(fd);
return true;
}

// Program to load the GPU Perfetto producer .so and call start().
int main(int argc, char** argv) {
if (!writeToPidFile()) {
LOG_ERR("Could not open %s", kPidFileName);
std::abort();
}

dlerror();
FN_PTR startFunc = nullptr;
for (int i = 0; startFunc == nullptr && i < NELEM(kProducerPaths); i++) {
startFunc = loadLibrary(kProducerPaths[i]);
}

if (startFunc == nullptr) {
LOG_ERR("Did not find the producer library");
LOG_ERR("LD_LIBRARY_PATH=%s", getenv("LD_LIBRARY_PATH"));
std::abort();
}

LOG_INFO("Calling start at %p", startFunc);
(*startFunc)();
LOG_WARN("Producer has exited.");

return 0;
}
6 changes: 4 additions & 2 deletions scripts/android.py
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ def main():

print(f"Using {tool} : {path}")

cmake_install_dir = RepoRelative('build-android/libs')
cmake_install_dir = RepoRelative('build-android/install')

# Delete install directory since it could contain files from old runs
if os.path.isdir(cmake_install_dir):
Expand All @@ -93,7 +93,8 @@ def main():

for abi in android_abis:
build_dir = RepoRelative(f'build-android/cmake/{abi}')
lib_dir = f'lib/{abi}'
lib_dir = f'{abi}/lib'
bin_dir = f'{abi}/bin'

if clean:
print("Deleting CMakeCache.txt")
Expand All @@ -111,6 +112,7 @@ def main():
cmake_cmd += f' -D CMAKE_TOOLCHAIN_FILE={android_toolchain}'
cmake_cmd += f' -D CMAKE_ANDROID_ARCH_ABI={abi}'
cmake_cmd += f' -D CMAKE_INSTALL_LIBDIR={lib_dir}'
cmake_cmd += f' -D CMAKE_INSTALL_BINDIR={bin_dir}'
cmake_cmd += f' -D BUILD_TESTS={build_tests}'
cmake_cmd += f' -D CMAKE_ANDROID_STL_TYPE=c++_static'

Expand Down
Loading