Merge pull request #2309 from mitza-oci/warnings
[ACE_TAO.git] / ACE / bin / PerlACE / ProcessAndroid.pm
blobd13491d6ed6be5ca35eae574a5e78c6fc65937d6
1 #!/usr/bin/env perl
3 package PerlACE::ProcessAndroid;
5 use POSIX "sys_wait_h";
6 use File::Basename;
7 use File::Spec;
8 use FileHandle;
9 use Cwd;
10 use Config;
12 use strict;
14 ###############################################################################
16 ### Grab signal names
18 my @signame;
20 if (defined $Config{sig_name}) {
21 my $i = 0;
22 foreach my $name (split (' ', $Config{sig_name})) {
23 $signame[$i] = $name;
24 $i++;
27 else {
28 my $i;
29 for ($i = 0; $i < 255; ++$i) {
30 $signame[$i] = $i;
34 ###############################################################################
36 ### Constructor and Destructor
38 sub new
40 my $proto = shift;
41 my $class = ref ($proto) || $proto;
42 my $self = {};
44 $self->{TARGET} = shift;
45 $self->{RUNNING} = 0;
46 $self->{IGNOREEXESUBDIR} = 1;
47 $self->{IGNOREHOSTROOT} = 0;
48 $self->{PROCESS} = undef;
49 $self->{EXECUTABLE} = shift;
51 # Only set argument when they are really supplied via the
52 # CreateProcess call. If the weren't supplied, an error like
53 # Process_Android::HASH (0x...) is generated.
54 if (@_ == 1) {
55 $self->{ARGUMENTS} = shift;
57 else {
58 $self->{ARGUMENTS} = "";
60 $self->{FSROOT} = $ENV{'ANDROID_FS_ROOT'};
62 bless ($self, $class);
64 # copy the test executable to the target at forehand
65 $self->copy_executable ();
67 return $self;
70 sub DESTROY
72 my $self = shift;
74 if ($self->{RUNNING} == 1) {
75 print STDERR "ERROR: <", $self->{EXECUTABLE},
76 "> still running upon object destruction\n";
77 $self->Kill ();
80 if (defined $self->{SCRIPTFILE}) {
81 unlink $self->{SCRIPTFILE};
83 if (defined $self->{UNLINKLIST}) {
84 foreach my $ul (@{$self->{UNLINKLIST}}) {
85 unlink $ul;
90 ###############################################################################
92 sub Arguments
94 my $self = shift;
96 if (@_ != 0) {
97 $self->{ARGUMENTS} = shift;
98 if (defined $self->{SCRIPTFILE}) {
99 if (!defined $self->{UNLINKLIST}) {
100 $self->{UNLINKLIST} = ();
102 push(@{$self->{UNLINKLIST}}, $self->{SCRIPTFILE});
103 $self->{SCRIPTFILE} = undef;
107 return $self->{ARGUMENTS};
110 sub Executable
112 my $self = shift;
114 if (@_ != 0) {
115 $self->{EXECUTABLE} = shift;
116 if (defined $self->{SCRIPTFILE}) {
117 if (!defined $self->{UNLINKLIST}) {
118 $self->{UNLINKLIST} = ();
120 push(@{$self->{UNLINKLIST}}, $self->{SCRIPTFILE});
121 $self->{SCRIPTFILE} = undef;
123 # copy the (new) test executable to the target
124 # previously scanned .vxtest files and detected libraries
125 # will not be scanned/copied twice
126 $self->copy_executable ();
129 my $executable = $self->{EXECUTABLE};
131 # If the target's config has a different ACE_ROOT, rebase the executable
132 # from $ACE_ROOT to the target's root.
133 if (defined $self->{TARGET} &&
134 $self->{TARGET}->ACE_ROOT() ne $ENV{'ACE_ROOT'}) {
135 $executable = PerlACE::rebase_path ($executable,
136 $ENV{'ACE_ROOT'},
137 $self->{TARGET}->ACE_ROOT());
140 if ($self->{IGNOREEXESUBDIR}) {
141 return $executable;
144 my $basename = basename ($executable);
145 my $dirname = dirname ($executable).'/';
147 my $subdir = $PerlACE::Process::ExeSubDir;
148 if (defined $self->{TARGET} && defined $self->{TARGET}->{EXE_SUBDIR}) {
149 $subdir = $self->{TARGET}->{EXE_SUBDIR};
152 $executable = $dirname . $subdir . $basename;
154 return $executable;
157 sub Wait ($)
159 my $self = shift;
160 my $timeout = shift;
161 if (!defined $timeout || $timeout < 0) {
162 waitpid ($self->{PROCESS}, 0);
163 } else {
164 return $self->TimedWait($timeout);
168 # really only for internal use
169 sub check_return_value ($)
171 my $self = shift;
172 my $rc = shift;
174 if ($rc < 0x80) {
175 return $rc;
178 # Remember Core dump flag
179 my $dump = 0;
181 if ($rc & 0x80) {
182 $rc &= ~0x80;
183 $dump = 1;
186 # check for ABRT, KILL or TERM
187 if ($rc == 6 || $rc == 9 || $rc == 15) {
188 return 0;
191 print STDERR "ERROR: <", $self->{EXECUTABLE},
192 "> exited with ";
194 print STDERR "coredump from " if ($dump == 1);
196 print STDERR "signal $rc : ", $signame[$rc], "\n";
198 return 255;
201 sub TimedWait ($)
203 my $self = shift;
204 my $timeout = shift;
206 if ($PerlACE::Process::WAIT_DELAY_FACTOR > 0) {
207 $timeout *= $PerlACE::Process::WAIT_DELAY_FACTOR;
210 if (defined $ENV{'ACE_TEST_VERBOSE'} && $self->{PROCESS} > 0) {
211 print STDERR "Wait $timeout to finish executable $self->{PROCESS}. ";
212 print STDERR "RUNNING: $self->{RUNNING}\n";
215 # Multiply with 10 because we wait a tenth of a second each time
216 $timeout *= 10;
218 while ($timeout-- != 0 && $self->{PROCESS} > 0 && $self->{RUNNING} == 1) {
219 my $pid = waitpid ($self->{PROCESS}, WNOHANG);
220 if ($pid != 0 && $? != -1) {
221 if (defined $ENV{'ACE_TEST_VERBOSE'} && $self->{PROCESS} > 0) {
222 print STDERR "Executable $self->{PROCESS} finished ($pid)\n";
224 last;
226 select(undef, undef, undef, 0.1);
229 # attempt to retrieve exitstatus from remote .rc file
230 my $shell = $ENV{'ANDROID_SDK_ROOT'} . '/platform-tools/adb shell';
231 my $rcfile = $self->{RCFILE};
232 ## wait max 5 * $PerlACE::Process::WAIT_DELAY_FACTOR sec for RC file to appear
233 my $start_tm = time ();
234 my $max_wait = 5;
235 if ($PerlACE::Process::WAIT_DELAY_FACTOR > 0) {
236 $max_wait *= $PerlACE::Process::WAIT_DELAY_FACTOR;
238 my $rc = -255;
239 while ((time() - $start_tm) < $max_wait) {
240 select(undef, undef, undef, 0.2);
241 $rc = int(`$shell 'if [ -e $rcfile -a -s $rcfile ] ; then cat $rcfile; rm -f $rcfile >/dev/null 2>&1; else echo -255; fi'`);
242 if ($rc != -255) {
243 return $self->check_return_value ($rc);
247 if (defined $ENV{'ACE_TEST_VERBOSE'}) {
248 print STDERR "Exit TimedWait with Process: $self->{PROCESS}, Running: $self->{RUNNING}\n";
251 return -1;
254 sub Kill ()
256 my $self = shift;
258 if ($self->{RUNNING} == 1) {
259 if (defined $ENV{'ACE_TEST_VERBOSE'}) {
260 print STDERR "Killing process <$self->{PROCESS}>\n";
262 # killing the adb process, not the actual test executable.
263 kill (1, $self->{PROCESS});
265 my $pid = waitpid ($self->{PROCESS}, WNOHANG);
266 if ($pid == -1) {
267 if (defined $ENV{'ACE_TEST_VERBOSE'}) {
268 print STDERR "Process <$self->{PROCESS}> already ended\n";
271 elsif ($pid == $self->{PROCESS}) {
272 if (defined $ENV{'ACE_TEST_VERBOSE'}) {
273 print STDERR "Process <$self->{PROCESS}> ended\n";
278 $self->{RUNNING} = 0;
281 sub WaitKill ($)
283 my $self = shift;
284 my $timeout = shift;
286 if ($self->{RUNNING} == 0) {
287 return 0;
290 my $status = $self->TimedWait ($timeout);
292 if ($status == -1) {
293 print STDERR "ERROR: $self->{EXECUTABLE} timedout\n";
294 $self->Kill ();
297 $self->{RUNNING} = 0;
299 return $status;
303 # Do a Spawn and immediately WaitKill
305 sub SpawnWaitKill ($)
307 my $self = shift;
308 my $timeout = shift;
310 if ($self->Spawn () == -1) {
311 return -1;
313 my $result = 0;
315 if ($self->{RUNNING} == 1) {
316 $result = $self->WaitKill ($timeout);
319 return $result;
322 sub TerminateWaitKill ($)
324 my $self = shift;
325 my $timeout = shift;
327 if ($self->{RUNNING}) {
328 print STDERR "INFO: $self->{EXECUTABLE} being killed.\n";
330 my $killcmd = $ENV{'ANDROID_SDK_ROOT'} . '/platform-tools/adb shell "kill -s TERM ' . $self->{REMOTE_PID} . '"';
331 system ($killcmd);
334 return $self->WaitKill ($timeout);
337 sub IgnoreExeSubDir
339 my $self = shift;
341 if (@_ != 0) {
342 $self->{IGNOREEXESUBDIR} = shift;
345 return $self->{IGNOREEXESUBDIR};
348 sub IgnoreHostRoot
350 my $self = shift;
352 if (@_ != 0) {
353 $self->{IGNOREHOSTROOT} = shift;
356 return $self->{IGNOREHOSTROOT};
359 sub Spawn ()
361 my $self = shift;
363 if ($self->{RUNNING} == 1) {
364 print STDERR "ERROR: Cannot Spawn: <", $self->Executable (),
365 "> already running\n";
366 return -1;
369 if (!defined $self->{EXECUTABLE}) {
370 print STDERR "ERROR: Cannot Spawn: No executable specified\n";
371 return -1;
374 if ($self->{IGNOREEXESUBDIR} == 0) {
375 if (!-f $self->Executable ()) {
376 print STDERR "ERROR: Cannot Spawn: <", $self->Executable (),
377 "> not found\n";
378 return -1;
381 my $status = 0;
383 my $fsroot_target = $ENV{'ANDROID_FS_ROOT'};
384 my $exe = $self->Executable ();
385 my $program = "$fsroot_target/".basename($exe);
387 my($test, $dir, $suffix) = fileparse($program);
389 my $local_xdir = cwd ();
391 if (!defined $self->{PIDFILE}) {
392 $self->{PIDFILE} = "$fsroot_target/ace-".rand(time).".pid";
394 if (!defined $self->{RCFILE}) {
395 $self->{RCFILE} = "$fsroot_target/ace-".rand(time).".rc";
397 if (!defined $self->{SCRIPTFILE}) {
398 $self->{SCRIPTFILE} = "$local_xdir/run-".rand(time).".sh";
400 ## create scriptfile
401 my $run_script =
402 # "if [ ! -e /tmp/.acerun ]; then mkdir /tmp/.acerun; fi\n".
403 "cd $fsroot_target\n".
404 "export LD_LIBRARY_PATH=$fsroot_target/lib:.:\$LD_LIBRARY_PATH\n".
405 "export PATH=\$PATH:$fsroot_target/lib:.\n".
406 "export ACE_ROOT=$fsroot_target\n";
408 if (defined $self->{TARGET} && defined $self->{TARGET}->{EXTRA_ENV}) {
409 my $x_env_ref = $self->{TARGET}->{EXTRA_ENV};
410 while ( my ($env_key, $env_value) = each(%$x_env_ref) ) {
411 $run_script .=
412 "export $env_key=\"$env_value\"\n";
415 $run_script .=
416 "./$test $self->{ARGUMENTS} &\n";
417 $run_script .=
418 "MY_PID=\$!\n".
419 "echo \$MY_PID > ".$self->{PIDFILE}."\n";
420 if (defined $ENV{'ACE_TEST_VERBOSE'}) {
421 $run_script .=
422 "echo INFO: Process started remote with pid [\$MY_PID]\n";
424 $run_script .=
425 "wait \$MY_PID\n";
426 $run_script .=
427 "MY_RC=\$?\n".
428 "echo \$MY_RC > ".$self->{RCFILE}."\n";
429 if (defined $ENV{'ACE_TEST_VERBOSE'}) {
430 $run_script .=
431 "echo INFO: Process [\$MY_PID] returned exit code [\$MY_RC]\n";
433 unless (open (RUN_SCRIPT, ">".$self->{SCRIPTFILE})) {
434 print STDERR "ERROR: Cannot Spawn: <", $self->Executable (),
435 "> failed to create ",$self->{SCRIPTFILE},"\n";
436 return -1;
438 print RUN_SCRIPT $run_script;
439 close RUN_SCRIPT;
441 if (defined $ENV{'ACE_TEST_VERBOSE'}) {
442 print STDERR "INFO: created run script [",$self->{SCRIPTFILE},"]\n", $run_script;
444 $self->PutFile ($self->{SCRIPTFILE}, "$fsroot_target/".basename($self->{SCRIPTFILE}));
446 my $adb_process = $ENV{'ANDROID_SDK_ROOT'} . "/platform-tools/adb";
447 my $cmd = $adb_process . ' shell "cd ' . $fsroot_target . ' && source ./' . basename($self->{SCRIPTFILE}) . '"';
449 FORK: {
450 if ($self->{PROCESS} = fork) {
451 bless $self;
453 elsif (defined $self->{PROCESS}) {
454 $self->{RUNNING} = 1;
456 if (defined $ENV{'ACE_TEST_VERBOSE'}) {
457 print STDERR "Start to execute: $cmd\n";
459 exec ( $cmd );
460 exit;
462 elsif ($! =~ /No more process/) {
463 sleep 5;
464 redo FORK;
466 else {
467 print STDERR "ERROR: Can't fork <" . $cmd . ">: $!\n";
471 my $shell = $adb_process . ' shell';
472 my $pidfile = $self->{PIDFILE};
473 ## wait max 10 * $PerlACE::Process::WAIT_DELAY_FACTOR sec for pid file to appear
474 my $start_tm = time ();
475 my $max_wait = 10;
476 if ($PerlACE::Process::WAIT_DELAY_FACTOR > 0) {
477 $max_wait *= $PerlACE::Process::WAIT_DELAY_FACTOR;
479 my $rc = 1;
480 while ((time() - $start_tm) < $max_wait) {
481 select(undef, undef, undef, 0.2);
482 $rc = int(`$shell 'if [ -e $pidfile -a -s $pidfile ] ; then cat $pidfile; rm -f $pidfile >/dev/null 2>&1; else echo 0; fi'`);
483 if ($rc != 0) {
484 $self->{REMOTE_PID} = $rc;
485 last;
488 if (!defined $self->{REMOTE_PID}) {
489 print STDERR "ERROR: Remote command failed <" . $test . ' ' . $self->{ARGUMENTS} . ">: $! No PID found.\n";
490 return -1;
493 $self->{RUNNING} = 1;
495 return 0;
498 sub copy_executable ($)
500 my $self = shift;
502 my $fsroot_target = $ENV{'ANDROID_FS_ROOT'};
503 my $program = $self->Executable ();
504 # never copy program subdirectory if specified (like '../Generic_Servant/server')
505 my $exe = "$fsroot_target/".basename($program);
507 $self->{SHLIBS} = ();
508 $self->{VXTESTS} = ();
509 $self->{XLIBPATH} = ();
511 push (@{$self->{XLIBPATH}}, '.');
512 if (defined $self->{TARGET} && defined $self->{TARGET}->{LIBPATH}) {
513 foreach my $libpath (split(/:|;/, $self->{TARGET}->{LIBPATH})) {
514 push(@{$self->{XLIBPATH}}, $libpath);
518 $self->PutFile ("$program", $exe);
520 if ($PerlACE::Static == 0) {
521 # collect libraries from .vxtest file
522 $self->process_vxtest ($program.'.vxtest');
523 # collect libraries from extra lib paths (might be dynamically loaded)
524 $self->collect_extra_libs ();
525 # collect any runtime lib dependencies specified
526 $self->collect_runtime_libs ();
527 # copy all collected libraries
528 foreach my $lib (@{$self->{SHLIBS}}) {
529 $self->PutFile ($lib, "$self->{FSROOT}/lib/".basename($lib));
531 # handle defined system libraries
532 if (defined $self->{TARGET} && defined $self->{TARGET}->{SYSTEM_LIBS}) {
533 $self->copy_system_libs ($self->{TARGET}->{SYSTEM_LIBS});
538 sub process_vxtest ($)
540 my $self = shift;
541 my $newvxtest = shift;
543 foreach my $vxtest (@{$self->{VXTESTS}}) {
544 if ($vxtest eq $newvxtest) {
545 return;
548 if (defined $ENV{'ACE_TEST_VERBOSE'}) {
549 print STDERR "Processing vxtest file $newvxtest\n";
551 $self->collect_vxtest_libs ($newvxtest);
554 sub add_unique_lib ($)
556 my $self = shift;
557 my $newlib = shift;
559 foreach my $lib (@{$self->{SHLIBS}}) {
560 if ($lib eq $newlib) {
561 return 0;
564 if (defined $ENV{'ACE_TEST_VERBOSE'}) {
565 print STDERR "Collecting library $newlib\n";
567 push(@{$self->{SHLIBS}}, $newlib);
568 return 1;
571 sub collect_vxtest_libs ()
573 my $self = shift;
574 my $vxtestfile = shift;
575 my $fh = new FileHandle;
577 if (defined $ENV{'ACE_TEST_VERBOSE'}) {
578 print STDERR "Analyzing vxtest file <$vxtestfile>\n";
581 if (open ($fh, $vxtestfile)) {
582 my $line1 = <$fh>;
583 chomp $line1;
584 if (defined $ENV{'ACE_TEST_VERBOSE'}) {
585 print STDERR "Analyzing vxtest file: Found line $line1\n";
587 while(<$fh>) {
588 $line1 = $_;
589 chomp $line1;
590 if (defined $ENV{'ACE_TEST_VERBOSE'}) {
591 print STDERR "Analyzing vxtest file: Found line $line1\n";
594 $self->collect_vxtest_lib ($line1);
597 close $fh;
600 sub collect_vxtest_lib ($)
602 my $self = shift;
603 my $name = shift;
604 my $query;
605 my @libpaths = ("$ENV{'ACE_ROOT'}/lib");
607 push (@libpaths, @{$self->{XLIBPATH}});
609 foreach my $libpath (@libpaths) {
610 $query = "$libpath/lib$name.so";
611 if (-e $query) {
612 if (defined $ENV{'ACE_TEST_VERBOSE'}) {
613 print STDERR "Found $name in library directory $libpath\n";
615 # look for versioned and non-versioned filenames
616 my @files = glob ($query . '*');
617 foreach my $file (@files) {
618 $self->add_unique_lib ($file);
624 sub collect_extra_libs ()
626 my $self = shift;
627 # treat current dir as extra libpath
628 my @libpaths = (@{$self->{XLIBPATH}});
629 my $query;
630 my $vxtest;
632 if (defined $ENV{'ACE_TEST_VERBOSE'}) {
633 print STDERR "Inspecting libpaths (@libpaths) for extra libraries\n";
636 foreach my $libpath (@libpaths) {
637 # look for versioned and non-versioned libraries
638 $query = "$libpath/lib*.so*";
639 my @files = glob ($query);
640 foreach my $file (@files) {
641 if ($self->add_unique_lib ($file) == 1) {
642 # check for possible .vxtest for new lib dependency
643 $vxtest = basename ($file);
644 $vxtest =~ s/^lib(.*)[\.]so([\.].*)?$/\1/;
645 if (-e "$libpath/$vxtest.vxtest") {
646 # process .vxtest file if not yet processed before
647 $self->process_vxtest ("$libpath/$vxtest.vxtest");
654 sub collect_runtime_libs ()
656 my $self = shift;
657 # only need to test ACE_ROOT/lib since all libs from '.' and extra libpaths are copied already
658 my @libpaths = ("$ENV{'ACE_ROOT'}/lib");
659 my $query;
661 if (defined $self->{TARGET} && defined $self->{TARGET}->{RUNTIME_LIBDEP}) {
663 foreach my $runtimelib (@{$self->{TARGET}->{RUNTIME_LIBDEP}}) {
665 if (-e $runtimelib) {
666 $self->add_unique_lib ($runtimelib);
667 } else {
669 if (defined $ENV{'ACE_TEST_VERBOSE'}) {
670 print STDERR "Inspecting libpaths (@libpaths) for runtime libe $runtimelib\n";
673 foreach my $libpath (@libpaths) {
674 # look for versioned and non-versioned libraries
675 $query = "$libpath/lib$runtimelib.so*";
676 my @files = glob ($query);
677 foreach my $file (@files) {
678 $self->add_unique_lib ($file);
686 sub copy_system_libs ()
688 my $self = shift;
689 my $syslibs = shift;
690 my @liblist = split (',', $syslibs);
691 foreach my $lib (@liblist) {
692 if (-e $lib) {
693 if (defined $ENV{'ACE_TEST_VERBOSE'}) {
694 print STDERR "Found system library $lib\n";
696 $self->PutFile ($lib, "$self->{FSROOT}/lib/" . basename ($lib));
697 } else {
698 print STDERR "Cannot find system library $lib!\n";
703 sub PutFile ($)
705 my $self = shift;
706 my $src = shift;
707 my $dest = shift;
709 if (defined $self->{TARGET}) {
710 return $self->{TARGET}->PutLib($src, $dest);
711 } else {
712 my $silent;
714 if (!defined $ENV{'ACE_TEST_VERBOSE'}) {
715 $silent = "2> /dev/null"
718 my $adb_process = $ENV{'ANDROID_SDK_ROOT'} . "/platform-tools/adb";
720 my $cmd = "$adb_process" . ' push '. "\"$src\" \"$dest\" $silent";
722 if (defined $ENV{'ACE_TEST_VERBOSE'}) {
723 print STDERR "PutFile cmd: $cmd\n";
726 system ( $cmd );
727 if ($? != 0) {
728 return -1;
730 return 0;