Skip to content

Commit 296d854

Browse files
dellis1972jonpryor
authored andcommitted
[Xamarin.Android.Build.Tasks] Hitting "System.IO.IOException: Too many open files" when building a large app with AOT and all supported architectures (#493)
Fixes: https://bugzilla.xamarin.com/show_bug.cgi?id=53122 There is a problem with libzip in that is does not have an API for Flushing the current items in memory to disk. This was why ZipArchiveEx was introduced in commit 9166e03. This commit reworks the BuildApk task to make sure of this new functinality and to periodically flush the zip to disk. This will reduce the chances of running out of memory. It also adds a unit test which generates and builds an app which has a large number of refernces and assets. This app also gets AOT'd so it should be pushing the system to the limit. Also added code to make sure the cross tools and llc have execute permissions. Added code to make sure we dispose of each process in the Aapt and Aot tasks. This is to ensure any files or pipes these processed have are removed as soon as possible. Updated the unix-distribution-setup.targets to ensure that the cross-arm tooling and llc have the correct execute permissions on MacOS and Linux.
1 parent 766c55a commit 296d854

File tree

8 files changed

+270
-87
lines changed

8 files changed

+270
-87
lines changed

build-tools/unix-distribution-setup/unix-distribution-setup.targets

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,14 @@
99
Condition=" '$(HostOS)' != 'Windows' "
1010
Command="chmod +x $(OutputPath)bin\generator"
1111
/>
12+
<Exec
13+
Condition=" '$(HostOS)' != 'Windows' "
14+
Command="chmod +x $(OutputPath)bin\cross*"
15+
/>
16+
<Exec
17+
Condition=" '$(HostOS)' != 'Windows' "
18+
Command="chmod +x $(OutputPath)bin\llc"
19+
/>
1220
</Target>
1321

1422
<Target Name="Clean">

src/Xamarin.Android.Build.Tasks/Tasks/Aapt.cs

Lines changed: 31 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -99,36 +99,37 @@ bool RunAapt (string commandLine)
9999
WindowStyle = ProcessWindowStyle.Hidden,
100100
};
101101

102-
var proc = new Process ();
103-
proc.OutputDataReceived += (sender, e) => {
104-
if (e.Data != null)
105-
LogEventsFromTextOutput (e.Data, MessageImportance.Normal);
106-
else
107-
stdout_completed.Set ();
108-
};
109-
proc.ErrorDataReceived += (sender, e) => {
110-
if (e.Data != null)
111-
LogEventsFromTextOutput (e.Data, MessageImportance.Normal);
112-
else
113-
stderr_completed.Set ();
114-
};
115-
proc.StartInfo = psi;
116-
proc.Start ();
117-
proc.BeginOutputReadLine ();
118-
proc.BeginErrorReadLine ();
119-
Token.Register (() => {
120-
try {
121-
proc.Kill ();
122-
} catch (Exception) {
123-
}
124-
});
125-
LogDebugMessage ("Executing {0}", commandLine);
126-
proc.WaitForExit ();
127-
if (psi.RedirectStandardError)
128-
stderr_completed.WaitOne (TimeSpan.FromSeconds (30));
129-
if (psi.RedirectStandardOutput)
130-
stdout_completed.WaitOne (TimeSpan.FromSeconds (30));
131-
return proc.ExitCode == 0;
102+
using (var proc = new Process ()) {
103+
proc.OutputDataReceived += (sender, e) => {
104+
if (e.Data != null)
105+
LogEventsFromTextOutput (e.Data, MessageImportance.Normal);
106+
else
107+
stdout_completed.Set ();
108+
};
109+
proc.ErrorDataReceived += (sender, e) => {
110+
if (e.Data != null)
111+
LogEventsFromTextOutput (e.Data, MessageImportance.Normal);
112+
else
113+
stderr_completed.Set ();
114+
};
115+
proc.StartInfo = psi;
116+
proc.Start ();
117+
proc.BeginOutputReadLine ();
118+
proc.BeginErrorReadLine ();
119+
Token.Register (() => {
120+
try {
121+
proc.Kill ();
122+
} catch (Exception) {
123+
}
124+
});
125+
LogDebugMessage ("Executing {0}", commandLine);
126+
proc.WaitForExit ();
127+
if (psi.RedirectStandardError)
128+
stderr_completed.WaitOne (TimeSpan.FromSeconds (30));
129+
if (psi.RedirectStandardOutput)
130+
stdout_completed.WaitOne (TimeSpan.FromSeconds (30));
131+
return proc.ExitCode == 0;
132+
}
132133
}
133134

134135
bool ExecuteForAbi (string cmd, string currentResourceOutputFile)

src/Xamarin.Android.Build.Tasks/Tasks/Aot.cs

Lines changed: 28 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -434,6 +434,8 @@ IEnumerable<Config> GetAotConfigs ()
434434

435435
bool RunAotCompiler (string assembliesPath, string aotCompiler, string aotOptions, string assembly, CancellationToken token)
436436
{
437+
var stdout_completed = new ManualResetEvent (false);
438+
var stderr_completed = new ManualResetEvent (false);
437439
var psi = new ProcessStartInfo () {
438440
FileName = aotCompiler,
439441
Arguments = aotOptions + " \"" + assembly + "\"",
@@ -453,16 +455,32 @@ bool RunAotCompiler (string assembliesPath, string aotCompiler, string aotOption
453455
LogDebugMessage ("[AOT] MONO_PATH=\"{0}\" MONO_ENV_OPTIONS=\"{1}\" {2} {3}",
454456
psi.EnvironmentVariables ["MONO_PATH"], psi.EnvironmentVariables ["MONO_ENV_OPTIONS"], psi.FileName, psi.Arguments);
455457

456-
var proc = new Process ();
457-
proc.OutputDataReceived += OnAotOutputData;
458-
proc.ErrorDataReceived += OnAotErrorData;
459-
proc.StartInfo = psi;
460-
proc.Start ();
461-
proc.BeginOutputReadLine ();
462-
proc.BeginErrorReadLine ();
463-
token.Register (() => { try { proc.Kill (); } catch (Exception) {} });
464-
proc.WaitForExit ();
465-
return proc.ExitCode == 0;
458+
using (var proc = new Process ()) {
459+
proc.OutputDataReceived += (s, e) => {
460+
if (e.Data != null)
461+
OnAotOutputData (s, e);
462+
else
463+
stdout_completed.Set ();
464+
};
465+
proc.ErrorDataReceived += (s, e) => {
466+
if (e.Data != null)
467+
OnAotErrorData (s, e);
468+
else
469+
stderr_completed.Set ();
470+
};
471+
proc.StartInfo = psi;
472+
proc.Start ();
473+
proc.BeginOutputReadLine ();
474+
proc.BeginErrorReadLine ();
475+
token.Register (() => { try { proc.Kill (); } catch (Exception) { } });
476+
proc.WaitForExit ();
477+
if (psi.RedirectStandardError)
478+
stderr_completed.WaitOne (TimeSpan.FromSeconds (30));
479+
if (psi.RedirectStandardOutput)
480+
stdout_completed.WaitOne (TimeSpan.FromSeconds (30));
481+
return proc.ExitCode == 0;
482+
}
483+
GC.Collect ();
466484
}
467485

468486
void OnAotOutputData (object sender, DataReceivedEventArgs e)

0 commit comments

Comments
 (0)