Remove legacy Android codexd path

Co-authored-by: Codex <noreply@openai.com>
This commit is contained in:
Iliyan Malchev
2026-03-21 11:07:45 -07:00
parent 11b681883f
commit ef5894affc
12 changed files with 60 additions and 1071 deletions

File diff suppressed because it is too large Load Diff

View File

@@ -6,7 +6,6 @@
//! targets. Keeping that setup local avoids pulling the TUI's session-oriented logging machinery
//! into a one-shot CLI command while still producing a durable `codex-login.log` artifact that
//! support can request from users.
use codex_core::CodexAuth;
use codex_core::auth::AuthCredentialsStoreMode;
use codex_core::auth::AuthMode;
@@ -35,7 +34,6 @@ const CHATGPT_LOGIN_DISABLED_MESSAGE: &str =
const API_KEY_LOGIN_DISABLED_MESSAGE: &str =
"API key login is disabled. Use ChatGPT login instead.";
const LOGIN_SUCCESS_MESSAGE: &str = "Successfully logged in";
/// Installs a small file-backed tracing layer for direct `codex login` flows.
///
/// This deliberately duplicates a narrow slice of the TUI logging setup instead of reusing it

View File

@@ -577,8 +577,8 @@ mod tests {
#[test]
fn parse_socket_endpoint_preserves_filesystem_paths() {
assert_eq!(
parse_socket_endpoint(Path::new("/tmp/codexd.sock")).expect("socket endpoint"),
UnixSocketEndpoint::Filesystem(PathBuf::from("/tmp/codexd.sock")),
parse_socket_endpoint(Path::new("/tmp/openai.sock")).expect("socket endpoint"),
UnixSocketEndpoint::Filesystem(PathBuf::from("/tmp/openai.sock")),
);
}

View File

@@ -37,6 +37,7 @@ use crate::auth::UnauthorizedRecovery;
use crate::auth_env_telemetry::AuthEnvTelemetry;
use crate::auth_env_telemetry::collect_auth_env_telemetry;
use crate::http_transport::build_api_transport;
use crate::openai_socket::should_route_via_openai_socket_proxy;
use codex_api::CompactClient as ApiCompactClient;
use codex_api::CompactionInput as ApiCompactionInput;
use codex_api::MemoriesClient as ApiMemoriesClient;
@@ -511,7 +512,8 @@ impl ModelClient {
///
/// WebSocket use is controlled by provider capability and session-scoped fallback state.
pub fn responses_websocket_enabled(&self) -> bool {
if !self.state.provider.supports_websockets
if should_route_via_openai_socket_proxy()
|| !self.state.provider.supports_websockets
|| self.state.disable_websockets.load(Ordering::Relaxed)
|| (*CODEX_RS_SSE_FIXTURE).is_some()
{
@@ -526,9 +528,13 @@ impl ModelClient {
/// This centralizes setup used by both prewarm and normal request paths so they stay in
/// lockstep when auth/provider resolution changes.
async fn current_client_setup(&self) -> Result<CurrentClientSetup> {
let auth = match self.state.auth_manager.as_ref() {
Some(manager) => manager.auth().await,
None => None,
let auth = if should_route_via_openai_socket_proxy() {
None
} else {
match self.state.auth_manager.as_ref() {
Some(manager) => manager.auth().await,
None => None,
}
};
let api_provider = self
.state

View File

@@ -83,6 +83,7 @@ use crate::config::types::McpServerConfig;
use crate::config::types::McpServerTransportConfig;
use crate::connectors::is_connector_id_allowed;
use crate::connectors::sanitize_name;
use crate::openai_socket::should_route_via_openai_socket_proxy;
/// Delimiter used to separate the server name from the tool name in a fully
/// qualified tool name.
@@ -1455,6 +1456,11 @@ async fn make_rmcp_client(
env_http_headers,
bearer_token_env_var,
} => {
if should_route_via_openai_socket_proxy() {
return Err(StartupOutcomeError::from(anyhow!(
"streamable HTTP MCP servers are disabled when routing through an OpenAI socket proxy"
)));
}
let resolved_bearer_token =
match resolve_bearer_token(server_name, bearer_token_env_var.as_deref()) {
Ok(token) => token,

View File

@@ -1,5 +1,4 @@
use std::ffi::OsString;
use std::path::Path;
use std::path::PathBuf;
pub const CODEX_OPENAI_UNIX_SOCKET_ENV_VAR: &str = "CODEX_OPENAI_UNIX_SOCKET";
@@ -11,43 +10,11 @@ pub fn openai_unix_socket_path() -> Option<PathBuf> {
.map(|value| value.trim().to_string())
.filter(|value| !value.is_empty())
.map(PathBuf::from)
.or_else(default_android_socket_path)
}
pub fn should_route_via_codexd() -> bool {
(openai_unix_socket_path().is_some()
|| should_use_agent_auth_proxy_env(std::env::var_os(CODEX_USE_AGENT_AUTH_PROXY_ENV_VAR)))
&& !is_codexd_process()
}
fn is_codexd_process() -> bool {
std::env::args_os()
.next()
.and_then(|arg0| {
Path::new(&arg0)
.file_name()
.and_then(|name| name.to_str())
.map(str::to_string)
})
.is_some_and(|arg0| arg0.contains("codexd"))
}
#[cfg(target_os = "android")]
fn default_android_socket_path() -> Option<PathBuf> {
const CANDIDATES: [&str; 2] = [
"/data/data/com.openai.codexd/files/codexd.sock",
"/data/user/0/com.openai.codexd/files/codexd.sock",
];
CANDIDATES
.iter()
.map(PathBuf::from)
.find(|path| path.exists())
}
#[cfg(not(target_os = "android"))]
fn default_android_socket_path() -> Option<PathBuf> {
None
pub fn should_route_via_openai_socket_proxy() -> bool {
openai_unix_socket_path().is_some()
|| should_use_agent_auth_proxy_env(std::env::var_os(CODEX_USE_AGENT_AUTH_PROXY_ENV_VAR))
}
fn should_use_agent_auth_proxy_env(value: Option<OsString>) -> bool {

View File

@@ -25,6 +25,7 @@ use crate::auth::storage::AuthStorageBackend;
use crate::auth::storage::create_auth_storage;
use crate::auth::util::try_parse_error_message;
use crate::default_client::create_client;
use crate::openai_socket::should_route_via_openai_socket_proxy;
use crate::token_data::KnownPlan as InternalKnownPlan;
use crate::token_data::PlanType as InternalPlanType;
use crate::token_data::TokenData;
@@ -1127,6 +1128,9 @@ impl AuthManager {
/// For stale managed ChatGPT auth, first performs a guarded reload and then
/// refreshes only if the on-disk auth is unchanged.
pub async fn auth(&self) -> Option<CodexAuth> {
if should_route_via_openai_socket_proxy() {
return self.auth_cached();
}
let auth = self.auth_cached()?;
if Self::is_stale_for_proactive_refresh(&auth)
&& let Err(err) = self.refresh_token().await
@@ -1312,6 +1316,10 @@ impl AuthManager {
/// can assume that some other instance already refreshed it. If the persisted
/// token is the same as the cached, then ask the token authority to refresh.
pub async fn refresh_token(&self) -> Result<(), RefreshTokenError> {
let _refresh_guard = self.refresh_lock.lock().await;
if should_route_via_openai_socket_proxy() {
return Ok(());
}
let _refresh_guard = self.refresh_lock.lock().await;
let auth_before_reload = self.auth_cached();
if auth_before_reload

View File

@@ -31,6 +31,7 @@ use codex_core::default_client::set_default_client_residency_requirement;
use codex_core::find_thread_path_by_id_str;
use codex_core::find_thread_path_by_name_str;
use codex_core::format_exec_policy_error_with_source;
use codex_core::openai_socket::openai_unix_socket_path;
use codex_core::path_utils;
use codex_core::read_session_meta_line;
use codex_core::state_db::get_state_db;
@@ -644,7 +645,7 @@ async fn run_ratatui_app(
/*enable_codex_api_key_env*/ false,
initial_config.cli_auth_credentials_store_mode,
);
let login_status = get_login_status(&initial_config);
let login_status = get_login_status(&initial_config).await;
let should_show_trust_screen_flag = should_show_trust_screen(&initial_config);
let should_show_onboarding =
should_show_onboarding(login_status, &initial_config, should_show_trust_screen_flag);
@@ -1215,11 +1216,15 @@ fn determine_alt_screen_mode(no_alt_screen: bool, tui_alternate_screen: AltScree
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum LoginStatus {
AuthMode(AuthMode),
ExternalProxy,
NotAuthenticated,
}
fn get_login_status(config: &Config) -> LoginStatus {
async fn get_login_status(config: &Config) -> LoginStatus {
if config.model_provider.requires_openai_auth {
if openai_unix_socket_path().is_some() {
return LoginStatus::ExternalProxy;
}
// Reading the OpenAI API key is an async operation because it may need
// to refresh the token. Block on it.
let codex_home = config.codex_home.clone();

View File

@@ -7,6 +7,7 @@ use chrono::Duration;
use chrono::Utc;
use codex_core::config::Config;
use codex_core::default_client::create_client;
use codex_core::openai_socket::should_route_via_openai_socket_proxy;
use serde::Deserialize;
use serde::Serialize;
use std::path::Path;
@@ -15,6 +16,9 @@ use std::path::PathBuf;
use crate::version::CODEX_CLI_VERSION;
pub fn get_upgrade_version(config: &Config) -> Option<String> {
if should_route_via_openai_socket_proxy() {
return None;
}
if !config.check_for_update_on_startup {
return None;
}

View File

@@ -49,7 +49,7 @@ The current repo now contains these implementation slices:
cross-app bind or raw local sockets.
- The session bridge now exposes a **narrow Responses transport** owned by the
Agent app itself, so Genie model traffic no longer depends on any separate
`codexd` socket service.
sidecar socket service.
- The Genie runtime now keeps host dynamic tools limited to framework-only
detached-target controls and frame capture, while standard Android shell and
device commands stay in the normal Codex tool path.
@@ -69,9 +69,9 @@ The current repo now contains these implementation slices:
`am start --user 0 ...`.
The Android app now owns auth, runtime status, and Genie Responses forwarding
directly through the hosted Agent runtime. The standalone Rust `codexd`
service/client split remains only as a legacy compatibility path outside the
Agent/Genie APK flow.
directly through the hosted Agent runtime. The older standalone
service/client split has been removed from the repo and is no longer part of
the Android Agent/Genie flow.
## Fixed Architecture Decisions
@@ -158,7 +158,7 @@ Agent/Genie APK flow.
- Hosted `codex app-server` inside Genie, with model traffic routed through a
Genie-local proxy backed by the Agent framework session bridge
- Agent-owned `/v1/responses` proxying in
`android/app/src/main/java/com/openai/codexd/AgentResponsesProxy.kt`
`android/app/src/main/java/com/openai/codex/agent/AgentResponsesProxy.kt`
- Framework-only Android dynamic tools registered on the Genie Codex thread with:
- detached target show/hide/attach/close
- detached frame capture

View File

@@ -6,6 +6,7 @@
- Treat keyring storage as unsupported on Android and use file-backed storage instead.
- Add a `just android-build` helper that uses `cargo-ndk` to build `codex` for `arm64-v8a` and `x86_64` (API 26).
- Document build and run steps for pushing the binary to a device.
- Build the Android Agent/Genie apps directly on `codex`.
## Prerequisites
@@ -32,6 +33,10 @@ For faster local iteration, you can skip Android release LTO:
```bash
CODEX_ANDROID_SKIP_LTO=1 just android-build
```
The Agent and Genie APKs now package only `codex`, so Android app builds require
only `just android-build`.
Build the Android Agent/Genie prototype APKs with the Android Agent Platform
stub SDK:
@@ -50,6 +55,7 @@ The Agent/Genie prototype modules also require
Gradle can compile against the stub SDK jar. The Agent APK and Genie APK both
package the Android `codex` binary as `libcodex.so`, so `just android-build`
must run before `:app:assembleDebug` and `:genie:assembleDebug`.
If `cargo-ndk` cannot find your NDK, set:
```bash
@@ -60,16 +66,16 @@ Build outputs:
- `target/android/aarch64-linux-android/release/codex`
- `target/android/x86_64-linux-android/release/codex`
## Run On Device
Example for `arm64-v8a`:
```bash
adb push target/android/aarch64-linux-android/release/codex /data/local/tmp/codex
adb shell chmod +x /data/local/tmp/codex
adb shell /data/local/tmp/codex --help
adb push target/android/aarch64-linux-android/release/codex /data/local/tmp/codex-bin
adb shell chmod +x /data/local/tmp/codex-bin
adb shell /data/local/tmp/codex-bin --help
```
## Authentication on Android
There are two reliable approaches when running the CLI from `adb shell`:
@@ -77,9 +83,10 @@ There are two reliable approaches when running the CLI from `adb shell`:
1) ChatGPT login via device code (recommended)
```bash
adb shell /data/local/tmp/codex --device-auth
adb shell /data/local/tmp/codex-bin --device-auth
```
This prints a URL and code. Open the URL on your host and enter the code.
The Agent app now owns authentication directly through the hosted Agent runtime.
2) MCP OAuth login via host browser + `adb forward`
@@ -91,7 +98,7 @@ from host to device so the redirect can reach the device.
adb forward tcp:8765 tcp:8765
# Start the login; the URL will be printed.
adb shell /data/local/tmp/codex mcp login <server_name> --callback-port 8765 --host-browser
adb shell /data/local/tmp/codex-bin mcp login <server_name> --callback-port 8765 --host-browser
```
Open the printed URL on your host. When the provider redirects to

View File

@@ -84,6 +84,7 @@ android-build:
profile_args=(--profile android-release-no-lto)
fi
CARGO_TARGET_DIR=target/android cargo ndk --platform 26 -t arm64-v8a -t x86_64 build -p codex-cli "${profile_args[@]}" --bin codex
# Run the MCP server
mcp-server-run *args:
cargo run -p codex-mcp-server -- "$@"