public static string ExtractWorkingDirectory(string commandOutput, string packageName) { IEnumerable <string> allLines = commandOutput.GetLines(); // Linux will allow just about anything in a directory name as long as it is excaped. Android is much // more picky about package names. Let's reject characters which are invalid in a package name, highly // unlikely that any Android distribution would decide to use in the base directory, and likely to show // up in any debug spew we should ignore. char[] invalidPackageNameChars = { ' ', '\t', '*', '[', ']', '(', ')', '{', '}', ':' }; // run-as is giving debug spew on a Galaxy S6, so we need to look at all the lines, and find the one that could be the working directory IEnumerable <string> workingDirectoryLines = allLines.Where( line => line.Length > 0 && line[0] == '/' && line.IndexOfAny(invalidPackageNameChars) < 0 ); if (workingDirectoryLines.Count() == 1) { return(workingDirectoryLines.Single()); } RunAsOutputParser.ThrowIfRunAsErrors(commandOutput, packageName); throw new LauncherException(Telemetry.LaunchFailureCode.BadPwdOutput, string.Format(CultureInfo.CurrentCulture, LauncherResources.Error_ShellCommandBadResults, "pwd")); }
private string GetGdbServerPath(string workingDirectory, Device device) { // On Android, the files of an application are extracted to the system owned directory /data/app/<appname>-<int>/lib // For 32-bit shared libraries, Android will create a symlink from the app owned directory /data/data/<appname>/lib // to maintain backwards compatibility with previous API versions. // There is no such symlink for 64-bit libraries, since Android only supports 64-bit since API 21, at which point // the app owned directory was no longer used for libs. // check the legacy location for 32-bit libs string gdbServerPath = workingDirectory + "/lib/gdbserver"; string lsCommand = string.Format(CultureInfo.InvariantCulture, "ls {0}", gdbServerPath); string output = ExecCommand(lsCommand); if (string.Compare(output, gdbServerPath, StringComparison.Ordinal) != 0) { // <app data>/lib is not symlinked to system's app data directory (/data/app/<app package>/lib). // We copy gdbserver ourselves because of 2 reasons: // 1. the app user doesn't have permissions on /data/app/<app package>-<suffix>/lib (it's owned by system) // 2. we can't deterministically figure out the location where gdbserver is in /data/app because of the suffix, // which is used by Android to have multiple copies of the APK extracted in the system. string tmpGDBServer = string.Format(CultureInfo.InvariantCulture, "/data/local/tmp/gdbserver"); device.FileSystem.Upload(_installPaths.GDBServerPath, tmpGDBServer, true); // Files can't be executed from /data/local/tmp string dest = string.Format(CultureInfo.InvariantCulture, "{0}/gdbserver", workingDirectory); // Can't use cp since shell doesn't have permissions to /data/data/<app> // and the app uid doesn't have permissions to /data/local/tmp string copyGDBServerCommand = string.Format(CultureInfo.InvariantCulture, "cat {0} | run-as {1} /system/bin/sh -c \"cat > {2}\"", tmpGDBServer, _launchOptions.Package, dest); int rc = ExecCommand(copyGDBServerCommand, out output); RunAsOutputParser.ThrowIfRunAsErrors(output, _launchOptions.Package); if (rc != 0) { throw new LauncherException( Telemetry.LaunchFailureCode.NoGdbServer, string.Format(CultureInfo.InvariantCulture, LauncherResources.Error_ShellCommandFailed, copyGDBServerCommand, output)); } string chmodGDBServerCommand = string.Format(CultureInfo.InvariantCulture, "run-as {0} chmod 700 {1}", _launchOptions.Package, dest); rc = ExecCommand(chmodGDBServerCommand, out output); RunAsOutputParser.ThrowIfRunAsErrors(output, _launchOptions.Package); if (rc != 0) { throw new LauncherException( Telemetry.LaunchFailureCode.NoGdbServer, string.Format(CultureInfo.InvariantCulture, LauncherResources.Error_ShellCommandFailed, chmodGDBServerCommand, output)); } gdbServerPath = dest; } return(gdbServerPath); }