3 package PerlACE
::ProcessAndroid
;
5 use POSIX
"sys_wait_h";
14 ###############################################################################
20 if (defined $Config{sig_name
}) {
22 foreach my $name (split (' ', $Config{sig_name
})) {
29 for ($i = 0; $i < 255; ++$i) {
34 ###############################################################################
36 ### Constructor and Destructor
41 my $class = ref ($proto) || $proto;
44 $self->{TARGET
} = shift;
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.
55 $self->{ARGUMENTS
} = shift;
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 ();
74 if ($self->{RUNNING
} == 1) {
75 print STDERR
"ERROR: <", $self->{EXECUTABLE
},
76 "> still running upon object destruction\n";
80 if (defined $self->{SCRIPTFILE
}) {
81 unlink $self->{SCRIPTFILE
};
83 if (defined $self->{UNLINKLIST
}) {
84 foreach my $ul (@
{$self->{UNLINKLIST
}}) {
90 ###############################################################################
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
};
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,
137 $self->{TARGET
}->ACE_ROOT());
140 if ($self->{IGNOREEXESUBDIR
}) {
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;
161 if (!defined $timeout || $timeout < 0) {
162 waitpid ($self->{PROCESS
}, 0);
164 return $self->TimedWait($timeout);
168 # really only for internal use
169 sub check_return_value
($)
178 # Remember Core dump flag
186 # check for ABRT, KILL or TERM
187 if ($rc == 6 || $rc == 9 || $rc == 15) {
191 print STDERR
"ERROR: <", $self->{EXECUTABLE
},
194 print STDERR
"coredump from " if ($dump == 1);
196 print STDERR
"signal $rc : ", $signame[$rc], "\n";
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
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";
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 ();
235 if ($PerlACE::Process
::WAIT_DELAY_FACTOR
> 0) {
236 $max_wait *= $PerlACE::Process
::WAIT_DELAY_FACTOR
;
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'`);
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";
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
);
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;
286 if ($self->{RUNNING
} == 0) {
290 my $status = $self->TimedWait ($timeout);
293 print STDERR
"ERROR: $self->{EXECUTABLE} timedout\n";
297 $self->{RUNNING
} = 0;
303 # Do a Spawn and immediately WaitKill
305 sub SpawnWaitKill
($)
310 if ($self->Spawn () == -1) {
315 if ($self->{RUNNING
} == 1) {
316 $result = $self->WaitKill ($timeout);
322 sub TerminateWaitKill
($)
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
} . '"';
334 return $self->WaitKill ($timeout);
342 $self->{IGNOREEXESUBDIR
} = shift;
345 return $self->{IGNOREEXESUBDIR
};
353 $self->{IGNOREHOSTROOT
} = shift;
356 return $self->{IGNOREHOSTROOT
};
363 if ($self->{RUNNING
} == 1) {
364 print STDERR
"ERROR: Cannot Spawn: <", $self->Executable (),
365 "> already running\n";
369 if (!defined $self->{EXECUTABLE
}) {
370 print STDERR
"ERROR: Cannot Spawn: No executable specified\n";
374 if ($self->{IGNOREEXESUBDIR
} == 0) {
375 if (!-f
$self->Executable ()) {
376 print STDERR
"ERROR: Cannot Spawn: <", $self->Executable (),
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";
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) ) {
412 "export $env_key=\"$env_value\"\n";
416 "./$test $self->{ARGUMENTS} &\n";
419 "echo \$MY_PID > ".$self->{PIDFILE
}."\n";
420 if (defined $ENV{'ACE_TEST_VERBOSE'}) {
422 "echo INFO: Process started remote with pid [\$MY_PID]\n";
428 "echo \$MY_RC > ".$self->{RCFILE
}."\n";
429 if (defined $ENV{'ACE_TEST_VERBOSE'}) {
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";
438 print RUN_SCRIPT
$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
}) . '"';
450 if ($self->{PROCESS
} = fork) {
453 elsif (defined $self->{PROCESS
}) {
454 $self->{RUNNING
} = 1;
456 if (defined $ENV{'ACE_TEST_VERBOSE'}) {
457 print STDERR
"Start to execute: $cmd\n";
462 elsif ($! =~ /No more process/) {
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 ();
476 if ($PerlACE::Process
::WAIT_DELAY_FACTOR
> 0) {
477 $max_wait *= $PerlACE::Process
::WAIT_DELAY_FACTOR
;
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'`);
484 $self->{REMOTE_PID
} = $rc;
488 if (!defined $self->{REMOTE_PID
}) {
489 print STDERR
"ERROR: Remote command failed <" . $test . ' ' . $self->{ARGUMENTS
} . ">: $! No PID found.\n";
493 $self->{RUNNING
} = 1;
498 sub copy_executable
($)
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
($)
541 my $newvxtest = shift;
543 foreach my $vxtest (@
{$self->{VXTESTS
}}) {
544 if ($vxtest eq $newvxtest) {
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
($)
559 foreach my $lib (@
{$self->{SHLIBS
}}) {
560 if ($lib eq $newlib) {
564 if (defined $ENV{'ACE_TEST_VERBOSE'}) {
565 print STDERR
"Collecting library $newlib\n";
567 push(@
{$self->{SHLIBS
}}, $newlib);
571 sub collect_vxtest_libs
()
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)) {
584 if (defined $ENV{'ACE_TEST_VERBOSE'}) {
585 print STDERR
"Analyzing vxtest file: Found line $line1\n";
590 if (defined $ENV{'ACE_TEST_VERBOSE'}) {
591 print STDERR
"Analyzing vxtest file: Found line $line1\n";
594 $self->collect_vxtest_lib ($line1);
600 sub collect_vxtest_lib
($)
605 my @libpaths = ("$ENV{'ACE_ROOT'}/lib");
607 push (@libpaths, @
{$self->{XLIBPATH
}});
609 foreach my $libpath (@libpaths) {
610 $query = "$libpath/lib$name.so";
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
()
627 # treat current dir as extra libpath
628 my @libpaths = (@
{$self->{XLIBPATH
}});
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
()
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");
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);
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
()
690 my @liblist = split (',', $syslibs);
691 foreach my $lib (@liblist) {
693 if (defined $ENV{'ACE_TEST_VERBOSE'}) {
694 print STDERR
"Found system library $lib\n";
696 $self->PutFile ($lib, "$self->{FSROOT}/lib/" . basename
($lib));
698 print STDERR
"Cannot find system library $lib!\n";
709 if (defined $self->{TARGET
}) {
710 return $self->{TARGET
}->PutLib($src, $dest);
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";