@@ -479,246 +479,128 @@ std::string PlatformAndroid::GetRunAs() {
479479 return run_as.str ();
480480}
481481
482- // Helper function to populate process status information from
483- // /proc/[pid]/status
484- void PlatformAndroid::PopulateProcessStatusInfo (
485- lldb::pid_t pid, ProcessInstanceInfo &process_info) {
486- // Read /proc/[pid]/status to get parent PID, UIDs, and GIDs
487- Status error;
488- AdbClientUP status_adb = GetAdbClient (error);
489- if (error.Fail ())
490- return ;
491-
492- std::string status_output;
493- StreamString status_cmd;
494- status_cmd.Printf (
495- " cat /proc/%llu/status 2>/dev/null | grep -E '^(PPid|Uid|Gid):'" ,
496- static_cast <unsigned long long >(pid));
497- Status status_error =
498- status_adb->Shell (status_cmd.GetData (), seconds (5 ), &status_output);
482+ // Check if a process looks like it needs cmdline supplementation.
483+ // Android apps spawned from zygote show as "app_process" or "zygote" initially.
484+ static bool NeedsCmdlineSupplement (const ProcessInstanceInfo &proc_info) {
485+ llvm::StringRef name =
486+ proc_info.GetExecutableFile ().GetFilename ().GetStringRef ();
487+ return name.contains (" app_process" ) || name.contains (" zygote" );
488+ }
499489
500- if (status_error.Fail () || status_output.empty ())
490+ // Fetch /proc/PID/cmdline for processes to get actual package names.
491+ // Android apps often show as "zygote" or "app_process" without this.
492+ static void SupplementWithCmdlineInfo (ProcessInstanceInfoList &proc_infos,
493+ AdbClient *adb, Log *log) {
494+ if (proc_infos.empty ())
501495 return ;
502496
503- llvm::SmallVector<llvm::StringRef, 16 > lines;
504- llvm::StringRef (status_output).split (lines, ' \n ' );
505-
506- for (llvm::StringRef line : lines) {
507- line = line.trim ();
508- if (line.starts_with (" PPid:" )) {
509- llvm::StringRef ppid_str = line.substr (5 ).trim ();
510- lldb::pid_t ppid;
511- if (llvm::to_integer (ppid_str, ppid))
512- process_info.SetParentProcessID (ppid);
513- } else if (line.starts_with (" Uid:" )) {
514- llvm::SmallVector<llvm::StringRef, 4 > uid_parts;
515- line.substr (4 ).trim ().split (uid_parts, ' \t ' , -1 , false );
516- if (uid_parts.size () >= 2 ) {
517- uint32_t uid, euid;
518- if (llvm::to_integer (uid_parts[0 ].trim (), uid))
519- process_info.SetUserID (uid);
520- if (llvm::to_integer (uid_parts[1 ].trim (), euid))
521- process_info.SetEffectiveUserID (euid);
522- }
523- } else if (line.starts_with (" Gid:" )) {
524- llvm::SmallVector<llvm::StringRef, 4 > gid_parts;
525- line.substr (4 ).trim ().split (gid_parts, ' \t ' , -1 , false );
526- if (gid_parts.size () >= 2 ) {
527- uint32_t gid, egid;
528- if (llvm::to_integer (gid_parts[0 ].trim (), gid))
529- process_info.SetGroupID (gid);
530- if (llvm::to_integer (gid_parts[1 ].trim (), egid))
531- process_info.SetEffectiveGroupID (egid);
532- }
497+ // Only supplement processes that look like zygote-spawned apps
498+ std::string pid_list;
499+ for (const auto &proc_info : proc_infos) {
500+ if (NeedsCmdlineSupplement (proc_info)) {
501+ if (!pid_list.empty ())
502+ pid_list += " " ;
503+ pid_list += std::to_string (proc_info.GetProcessID ());
533504 }
534505 }
535- }
536506
537- // Helper function to populate command line arguments from /proc/[pid]/cmdline
538- void PlatformAndroid::PopulateProcessCommandLine (
539- lldb::pid_t pid, ProcessInstanceInfo &process_info) {
540- // Read /proc/[pid]/cmdline to get command line arguments
541- Status error;
542- AdbClientUP cmdline_adb = GetAdbClient (error);
543- if (error.Fail ())
507+ if (pid_list.empty ())
544508 return ;
545509
546- std::string cmdline_output;
547- StreamString cmdline_cmd;
548- cmdline_cmd.Printf (" cat /proc/%llu/cmdline 2>/dev/null | tr '\\ 000' ' '" ,
549- static_cast <unsigned long long >(pid));
550- Status cmdline_error =
551- cmdline_adb->Shell (cmdline_cmd.GetData (), seconds (5 ), &cmdline_output);
552-
553- if (cmdline_error.Fail () || cmdline_output.empty ())
554- return ;
510+ // Use xargs -P to parallelize cmdline fetching (up to 8 concurrent reads)
511+ StreamString cmd;
512+ cmd.Printf (
513+ " echo '%s' | xargs -n 1 -P 8 sh -c "
514+ " 'echo \" $1:$(cat /proc/$1/cmdline 2>/dev/null | tr \"\\ 0\" \" \" )\" ' sh" ,
515+ pid_list.c_str ());
555516
556- cmdline_output = llvm::StringRef (cmdline_output).trim ().str ();
557- if (cmdline_output.empty ())
558- return ;
517+ std::string cmdline_output;
518+ Status error = adb->Shell (cmd.GetData (), seconds (5 ), &cmdline_output);
559519
560- llvm::SmallVector<llvm::StringRef, 16 > args;
561- llvm::StringRef (cmdline_output).split (args, ' ' , -1 , false );
562- if (args.empty ())
520+ if (error.Fail () || cmdline_output.empty ())
563521 return ;
564522
565- process_info.SetArg0 (args[0 ]);
566- Args process_args;
567- for (size_t i = 1 ; i < args.size (); i++) {
568- if (!args[i].empty ())
569- process_args.AppendArgument (args[i]);
570- }
571- process_info.SetArguments (process_args, false );
572- }
523+ llvm::SmallVector<llvm::StringRef, 256 > lines;
524+ llvm::StringRef (cmdline_output).split (lines, ' \n ' , -1 , false );
573525
574- // Helper function to populate architecture from /proc/[pid]/exe
575- void PlatformAndroid::PopulateProcessArchitecture (
576- lldb::pid_t pid, ProcessInstanceInfo &process_info) {
577- // Read /proc/[pid]/exe to get executable path for architecture detection
578- Status error;
579- AdbClientUP exe_adb = GetAdbClient (error);
580- if (error.Fail ())
581- return ;
526+ for (llvm::StringRef line : lines) {
527+ line = line.trim ();
528+ auto colon_pos = line.find (' :' );
529+ if (colon_pos == llvm::StringRef::npos)
530+ continue ;
582531
583- std::string exe_output;
584- StreamString exe_cmd;
585- exe_cmd.Printf (" readlink /proc/%llu/exe 2>/dev/null" ,
586- static_cast <unsigned long long >(pid));
587- Status exe_error = exe_adb->Shell (exe_cmd.GetData (), seconds (5 ), &exe_output);
532+ llvm::StringRef pid_str = line.substr (0 , colon_pos);
533+ llvm::StringRef cmdline = line.substr (colon_pos + 1 ).trim ();
588534
589- if (exe_error.Fail () || exe_output.empty ())
590- return ;
535+ lldb::pid_t pid;
536+ if (!llvm::to_integer (pid_str, pid) || cmdline.empty ())
537+ continue ;
591538
592- exe_output = llvm::StringRef (exe_output).trim ().str ();
593-
594- // Determine architecture from exe path
595- ArchSpec arch;
596- if (exe_output.find (" 64" ) != std::string::npos ||
597- exe_output.find (" arm64" ) != std::string::npos ||
598- exe_output.find (" aarch64" ) != std::string::npos) {
599- arch.SetTriple (" aarch64-unknown-linux-android" );
600- } else if (exe_output.find (" x86_64" ) != std::string::npos) {
601- arch.SetTriple (" x86_64-unknown-linux-android" );
602- } else if (exe_output.find (" x86" ) != std::string::npos ||
603- exe_output.find (" i686" ) != std::string::npos) {
604- arch.SetTriple (" i686-unknown-linux-android" );
605- } else {
606- // Default to armv7 for 32-bit ARM (most common on Android)
607- arch.SetTriple (" armv7-unknown-linux-android" );
539+ for (auto &proc_info : proc_infos) {
540+ if (proc_info.GetProcessID () != pid)
541+ continue ;
542+
543+ llvm::SmallVector<llvm::StringRef, 16 > args;
544+ cmdline.split (args, ' ' , -1 , false );
545+
546+ if (!args.empty ()) {
547+ proc_info.GetExecutableFile ().SetFile (args[0 ], FileSpec::Style::posix);
548+
549+ if (args.size () > 1 ) {
550+ Args process_args;
551+ for (size_t i = 1 ; i < args.size (); ++i) {
552+ if (!args[i].empty ())
553+ process_args.AppendArgument (args[i]);
554+ }
555+ proc_info.SetArguments (process_args, false );
556+ }
557+
558+ LLDB_LOGF (log,
559+ " PlatformAndroid::%s supplemented PID %llu with cmdline: %s" ,
560+ __FUNCTION__, static_cast <unsigned long long >(pid),
561+ cmdline.str ().c_str ());
562+ }
563+ break ;
564+ }
608565 }
609-
610- if (arch.IsValid ())
611- process_info.SetArchitecture (arch);
612566}
613567
614568uint32_t
615569PlatformAndroid::FindProcesses (const ProcessInstanceInfoMatch &match_info,
616570 ProcessInstanceInfoList &proc_infos) {
617571 proc_infos.clear ();
618572
619- // When LLDB is running natively on an Android device (IsHost() == true),
620- // use the parent class's standard Linux /proc enumeration. IsHost() is only
621- // true when compiled for Android (#if defined(__ANDROID__)), so calling
622- // PlatformLinux methods is safe (Android is Linux-based).
623573 if (IsHost ())
624574 return PlatformLinux::FindProcesses (match_info, proc_infos);
625575
626- // Remote Android platform: implement process name lookup using 'pidof' over
627- // adb.
628-
629- // LLDB stores the search name in GetExecutableFile() (even though it's
630- // actually a process name like "com.android.chrome" rather than an
631- // executable path). If no search name is provided, we can't use
632- // 'pidof', so return early with no results.
633- const ProcessInstanceInfo &match_process_info = match_info.GetProcessInfo ();
634- if (!match_process_info.GetExecutableFile () ||
635- match_info.GetNameMatchType () == NameMatch::Ignore) {
636- return 0 ;
637- }
638-
639- // Extract the process name to search for (typically an Android package name
640- // like "com.example.app" or binary name like "app_process64")
641- std::string process_name = match_process_info.GetExecutableFile ().GetPath ();
642- if (process_name.empty ())
643- return 0 ;
644-
645- // Use adb to find the process by name
646- Status error;
647- AdbClientUP adb (GetAdbClient (error));
648- if (error.Fail ()) {
649- Log *log = GetLog (LLDBLog::Platform);
650- LLDB_LOGF (log, " PlatformAndroid::%s failed to get ADB client: %s" ,
651- __FUNCTION__, error.AsCString ());
652- return 0 ;
653- }
654-
655- // Use 'pidof' command to get PIDs for the process name.
656- // Quote the process name to handle special characters (spaces, etc.)
657- std::string pidof_output;
658- StreamString command;
659- command.Printf (" pidof '%s'" , process_name.c_str ());
660- error = adb->Shell (command.GetData (), seconds (5 ), &pidof_output);
661-
662- if (error.Fail ()) {
663- Log *log = GetLog (LLDBLog::Platform);
664- LLDB_LOG (log, " PlatformAndroid::{} 'pidof {}' failed: {}" , __FUNCTION__,
665- process_name.c_str (), error.AsCString ());
666- return 0 ;
667- }
668-
669- // Parse PIDs from pidof output.
670- // Note: pidof can return multiple PIDs (space-separated) if multiple
671- // instances of the same executable are running.
672- pidof_output = llvm::StringRef (pidof_output).trim ().str ();
673- if (pidof_output.empty ()) {
674- Log *log = GetLog (LLDBLog::Platform);
675- LLDB_LOGF (log, " PlatformAndroid::%s no process found with name '%s'" ,
676- __FUNCTION__, process_name.c_str ());
576+ if (!m_remote_platform_sp)
677577 return 0 ;
678- }
679578
680- // Split the output by whitespace to handle multiple PIDs
681- llvm::SmallVector<llvm::StringRef, 8 > pid_strings;
682- llvm::StringRef (pidof_output).split (pid_strings, ' ' , -1 , false );
683-
684- Log *log = GetLog (LLDBLog::Platform);
579+ // For Android, we need to get cmdline info before doing name matching
580+ // because apps run as "zygote" but have package names in cmdline.
581+ ProcessInstanceInfoMatch broad_match_info = match_info;
582+ broad_match_info.SetNameMatchType (NameMatch::Ignore);
685583
686- // Process each PID and gather information
687- uint32_t num_matches = 0 ;
688- for (llvm::StringRef pid_str : pid_strings) {
689- pid_str = pid_str.trim ();
690- if (pid_str.empty ())
691- continue ;
584+ ProcessInstanceInfoList all_procs;
585+ uint32_t count =
586+ m_remote_platform_sp->FindProcesses (broad_match_info, all_procs);
692587
693- lldb::pid_t pid;
694- if (!llvm::to_integer (pid_str, pid)) {
695- LLDB_LOGF (log, " PlatformAndroid::%s failed to parse PID from: '%s'" ,
696- __FUNCTION__, pid_str.str ().c_str ());
697- continue ;
588+ if (count > 0 ) {
589+ Status error;
590+ AdbClientUP adb (GetAdbClient (error));
591+ if (error.Success ()) {
592+ Log *log = GetLog (LLDBLog::Platform);
593+ SupplementWithCmdlineInfo (all_procs, adb.get (), log);
698594 }
699595
700- ProcessInstanceInfo process_info;
701- process_info.SetProcessID (pid);
702- process_info.GetExecutableFile ().SetFile (process_name,
703- FileSpec::Style::posix);
704-
705- // Populate additional process information
706- PopulateProcessStatusInfo (pid, process_info);
707- PopulateProcessCommandLine (pid, process_info);
708- PopulateProcessArchitecture (pid, process_info);
709-
710- // Check if this process matches the criteria
711- if (match_info.Matches (process_info)) {
712- proc_infos.push_back (process_info);
713- num_matches++;
714-
715- LLDB_LOGF (log, " PlatformAndroid::%s found process '%s' with PID %llu" ,
716- __FUNCTION__, process_name.c_str (),
717- static_cast <unsigned long long >(pid));
596+ // Now apply the original name matching against supplemented process info
597+ for (auto &proc_info : all_procs) {
598+ if (match_info.Matches (proc_info))
599+ proc_infos.push_back (proc_info);
718600 }
719601 }
720602
721- return num_matches ;
603+ return proc_infos. size () ;
722604}
723605
724606std::unique_ptr<AdbSyncService> PlatformAndroid::GetSyncService (Status &error) {
0 commit comments