Android jar/dex method count on windows - java

I've seen some links for counting the methods on Linux and MacOS, but I haven't seen anything for Windows. How do you count a number of methods in a .dex or .jar file?

After unsuccessful search for a solution, I wrote two simple batch/shell scripts that do that.
The first one, methodcount.bat, checks if the file is .dex or .jar, and if it's a .jar file, it processes it with dx into dex file and then calls the second one, printhex.ps1, that actually checks the number of methods in the dex file - it reads 2 bytes beginning at 88 (little endian) and converts them into a decimal number.
To use this you to have dx somewhere in your path (it's in the android SDK build-tools/xx.x.x folder) and have PowerShell installed (it should already be installed on Windows 7/8).
Usage is very simple: methodcount.bat filename.dex|filename.jar.
Here are the scripts, but you can also find them on gist: https://gist.github.com/mrsasha/9f24e129ced1b1db791b.
methodcount.bat
#ECHO OFF
IF "%1"=="" GOTO MissingFileNameError
IF EXIST "%1" (GOTO ContinueProcessing) ELSE (GOTO FileDoesntExist)
:ContinueProcessing
set FileNameToProcess=%1
set FileNameForDx=%~n1.dex
IF "%~x1"==".dex" GOTO ProcessWithPowerShell
REM preprocess Jar with dx
IF "%~x1"==".jar" (
ECHO Processing Jar %FileNameToProcess% with DX!
CALL dx --dex --output=%FileNameForDx% %FileNameToProcess%
set FileNameToProcess=%FileNameForDx%
IF ERRORLEVEL 1 GOTO DxProcessingError
)
:ProcessWithPowerShell
ECHO Counting methods in DEX file %FileNameToProcess%
CALL powershell -noexit -executionpolicy bypass "& ".\printhex.ps1" %FileNameToProcess%
GOTO End
:MissingFileNameError
#ECHO Missing filename for processing
GOTO End
:DxProcessingError
#ECHO Error processing file %1% with dx!
GOTO End
:FileDoesntExist
#ECHO File %1% doesn't exist!
GOTO End
:End
printhex.ps1
<#
.SYNOPSIS
Outputs the number of methods in a dex file.
.PARAMETER Path
Specifies the path to a file. Wildcards are not permitted.
#>
param(
[parameter(Position=0,Mandatory=$TRUE)]
[String] $Path
)
if ( -not (test-path -literalpath $Path) ) {
write-error "Path '$Path' not found." -category ObjectNotFound
exit
}
$item = get-item -literalpath $Path -force
if ( -not ($? -and ($item -is [System.IO.FileInfo])) ) {
write-error "'$Path' is not a file in the file system." -category InvalidType
exit
}
if ( $item.Length -gt [UInt32]::MaxValue ) {
write-error "'$Path' is too large." -category OpenError
exit
}
$stream = [System.IO.File]::OpenRead($item.FullName)
$buffer = new-object Byte[] 2
$stream.Position = 88
$bytesread = $stream.Read($buffer, 0, 2)
$output = $buffer[0..1]
#("{1:X2} {0:X2}") -f $output
$outputdec = $buffer[1]*256 + $buffer[0]
"Number of methods is " + $outputdec
$stream.Close()

I see this question is old, but there's a Gradle plugin that will work on Windows which will report the method-reference count in an APK on each build: https://github.com/KeepSafe/dexcount-gradle-plugin.

Related

Perl system call to jar file failing in cron

I am trying to execute a perl script via a cron job that uses the system command to execute a java wrapper for boilerpipe. It fails when executed via cron. The script (simplified) is
my $link = "http://foo.bar"; # with a real link
my $cmdstring = 'java -jar boilerpipe-wrapper.jar url '.$link.' out.txt';
my $result = system($cmdstring);
if ($? == -1) {
print LOG "failed to execute system command: $!\n";
die;
}
elsif ($? & 127) {
printf LOG "child died with signal %d, %s coredump\n",
($? & 127), ($? & 128) ? 'with' : 'without';
die;
}
else {
printf LOG "child exited with value %d\n", $? >> 8;
die;
}
The die commands are in there for debugging purposes. What appears in LOG is
child exited with value 1
The crontab line is
24 7 * * * perl /home/retrievetext.pl >> /home/cron-msgs 2>&1
What appears in cron-msgs is
Error: unable to access jarfile boilerpipe-wrapper.jar
Died at /home/retrievetext.pl line 15
The ls -la for boilerpipe-wrapper.jar is
-rwxr-xr-x 1 steve sudo 1945275 Apr 29 03:53 boilerpipe-wrapper.jar
The Perl script and the system call work as expected when executed from the terminal. Anyone know what the problem is?

libc6-i386 installation on Yocto build

I'm trying add a Java installation on my Yocto build. I would like to run on my embedded system a Java application I developed but I can't correctly install Java.
When I try to run java I get the following:
./java: No such file or directory
I googled for a solution and found that I need to install libc6 32 bit version.
I proceeded to modify my local.conf file as following:
MACHINE ??= "intel-corei7-64"
require conf/multilib.conf
MULTILIBS = "multilib:lib32"
DEFAULTTUNE_virtclass-multilib-lib32 = "x86"
DISTRO ?= "poky"
PACKAGE_CLASSES ?= "package_rpm"
SDKMACHINE ?= "x86_64"
EXTRA_IMAGE_FEATURES ?= "debug-tweaks"
USER_CLASSES ?= "buildstats image-mklibs image-prelink"
PATCHRESOLVE = "noop"
BB_DISKMON_DIRS = "\
STOPTASKS,${TMPDIR},1G,100K \
STOPTASKS,${DL_DIR},1G,100K \
STOPTASKS,${SSTATE_DIR},1G,100K \
STOPTASKS,/tmp,100M,100K \
ABORT,${TMPDIR},100M,1K \
ABORT,${DL_DIR},100M,1K \
ABORT,${SSTATE_DIR},100M,1K \
ABORT,/tmp,10M,1K"
PACKAGECONFIG_append_pn-qemu-native = " sdl"
PACKAGECONFIG_append_pn-nativesdk-qemu = " sdl"
CONF_VERSION = "1"
CORE_IMAGE_EXTRA_INSTALL = " lib32-glibc"
CORE_IMAGE_EXTRA_INSTALL += "opencv opencv-samples libopencv-core-dev libopencv-highgui-dev libopencv-imgproc-dev libopencv-objdetect-dev libopencv-ml-dev"
But i get this error:
Build Configuration:
BB_VERSION = "1.32.0"
BUILD_SYS = "x86_64-linux"
NATIVELSBSTRING = "universal-4.8"
TARGET_SYS = "x86_64-poky-linux"
MACHINE = "intel-corei7-64"
DISTRO = "poky"
DISTRO_VERSION = "2.2.1"
TUNE_FEATURES = "m64 corei7"
TARGET_FPU = ""
meta
meta-poky
meta-yocto-bsp = "morty:924e576b8930fd2268d85f0b151e5f68a3c2afce"
meta-intel = "morty:6add41510412ca196efb3e4f949d403a8b6f35d7"
meta-oe = "morty:fe5c83312de11e80b85680ef237f8acb04b4b26e"
meta-intel-realsense = "morty:2c0dfe9690d2871214fba9c1c32980a5eb89a421"
Initialising tasks: 100% |#####################################################################################################################################################################################################| Time: 0:00:22
NOTE: Executing SetScene Tasks
NOTE: Executing RunQueue Tasks
ERROR: rmc-1.0-r0 do_package: QA Issue: rmc: Files/directories were installed but not shipped in any package:
/usr/lib
/usr/lib/librmclefi.a
/usr/lib/librsmpefi.a
Please set FILES such that these items are packaged. Alternatively if they are unneeded, avoid installing them or delete them within do_install.
rmc: 3 installed and not shipped files. [installed-vs-shipped]
ERROR: rmc-1.0-r0 do_package: Fatal QA errors found, failing task.
ERROR: rmc-1.0-r0 do_package: Function failed: do_package
ERROR: Logfile of failure stored in: /home/dalben/WorkingBuild/poky/filec/tmp/work/corei7-64-poky-linux/rmc/1.0-r0/temp/log.do_package.16424
ERROR: Task (/home/dalben/WorkingBuild/poky/meta-intel/common/recipes-bsp/rmc/rmc.bb:do_package) failed with exit code '1'
NOTE: Tasks Summary: Attempted 2954 tasks of which 2937 didn't need to be rerun and 1 failed.
Summary: 1 task failed:
/home/dalben/WorkingBuild/poky/meta-intel/common/recipes-bsp/rmc/rmc.bb:do_package
Summary: There were 3 ERROR messages shown, returning a non-zero exit code.
Any help is appreciated.
EDIT: Updated question here.
For your information, you will need to do a lot of work in putting Java into your image.
Your current image does not have any java related programs installed since I do not see meta-java in your compile process.
CORE_IMAGE_EXTRA_INSTALL is restricted to OE Core images; So if you have your own image recipe, the variable will does not work unless you inherit core-image.bbclass
Here is an example on putting "openjdk-7-jre" to the image: http://wiki.hioproject.org/index.php?title=OpenHAB:_WeMo_Switch
The key elements are: meta-java, meta-oracle-java .
You will need to add them to your conf/bblayers.conf
BBLAYERS = " \
${BSPDIR}/sources/meta-java \
${BSPDIR}/sources/meta-oracle-java \
"
In conf/local.conf, add this line to install openjdk-7-jre.
IMAGE_INSTALL_append = " openjdk-7-jre "
To add more on what you need, check on https://layers.openembedded.org/layerindex/branch/master/layers/

Code Signing JavaFX Executable with VBScript, the SignTool errors with Access Denied

Alright so I've finally figured out how to go about code-signing the executable created by the JavaFX Bundler BEFORE (I hope) it is placed by the INNO script into a setup file : There's just one problem :
I've broken myself into pieces trying to resolve this stupid problem but the Access Denied error keeps popping up. This is the VBScript I'm using to try and make this work.
Initially I thought it was a permission error but as I was able to successfully call the script elevated, and still got this error, I can only assume I am mistaken. So...
Can someone please tell me what it is I am doing wrong here?
<?xml version = "1.0" ?>
<package>
<job id="CodeSign">
<script language = "VBScript">
<![CDATA[
WScript.Echo "Setting bElevate to False. . ."
bElevate = false
If WScript.Arguments.Count > 0 Then
WScript.Echo "Arguments.Count > 0"
If WScript.Arguments(WScript.Arguments.Count-1) <> "|" Then
WScript.Echo "Arg N - 1 != ""|"" . . ."
bElevate = true
End If
End If
If bElevate Or WScript.Arguments.Count = 0 Then
WScript.Echo "Elevating . . ."
ElevateUAC
End If
Dim Shell
Set Shell = WScript.CreateObject("WScript.Shell")
Shell.Run "C:\Sign.bat ""Registration Test\Registration Test.exe""", 1, True
Set Shell = Nothing
Sub ElevateUAC
sParams = "|"
If WScript.Arguments.Count > 0 Then
For I = WScript.Arguments.Count - 1 to 0 Step -1
SParams = " " & WScript.Arugments(I) & sParams
Next
End If
Dim objShell
Set objShell = CreateObject("Shell.Application")
objShell.ShellExecute "wscript.exe", """" & WScript.ScriptFullName & """ """ & sParams & """", "", "runas", 1
WScript.Echo "Elevated . . ."
WScript.Quit
End Sub
]]>
</script>
</job>
</package>
Okay so I found it. This is pretty painful because there's (if I'm using this term in the correct context) "race conditions" here in that if the code signing doesn't finish before you start running the process again, it fails because it can't do anything with the .exe because it's being used by another process.
Turns out as long as your IDE is running in Admin (for Windows anyway) there's no need to elevate your script either.
Anyay, my problem was that the file was being set as Read-Only. VERY annoying but fortunately VBScript allows for you to change a files attributes so it was just a matter of doing that before trying to code-sign it :
<?xml version = "1.0" ?>
<package>
<job id="CodeSign">
<script language = "VBScript">
<![CDATA[
'Set File as Normal. . .
Dim objFSO, objFile
Set objFSO = CreateObject("Scripting.FileSystemObject")
Set objFile = objFSO.GetFile("<Relative Path>\<File.exe>")
objFile.Attributes = 0
Dim Shell
Set Shell = WScript.CreateObject("WScript.Shell")
Shell.Run "<Code Sign> ""<Relative Path>\<File.exe>""", 1, True
Set Shell = Nothing
Set objFSO = Nothing
Set objFile = Nothing
]]>
</script>
</job>
</package>
So now, finally, at LONG LAST we have a complete and viable answer to this, evidently very esoteric question that no one but myself has dealt with (or is a very closely guarded secret, I'm not sure which) : How do you code-sign the executable created by a JavaFX bundle before it gets stored?
Create a WSF file with either JavaScript or VBScript (your
preference)
Add the directory in which the file is being stored to the Class Path (for NetBeans you go to Tools -> Options -> Java Tab, select Add Directory next to Class Path, browse to the directory, and add it).
In your WSF file, in the Script section, get the file object and set its attributes to normal (0).
Then Shell.Run your preferred method of code signing applications. 1 is for showing the Code Sign window, True is to make the VBScript wait until it's finished to hopefully avoid a race condition.
The .exe will ALWAYS be stored one directory up from the WSF script file so the relative path is always going to be <FILENAME>\<FILENAME.exe>.
I really, REALLY hope this saves someone a LOT of grief some day...

Launching JRE in Linux from a FAT32 USB

I have a Java application installed on a USB which the user should be able to run from any OS.
For this,
I'm packaging a JRE instance on the USB along with my application.
I'm having a FAT32 file-system on the USB.
However, the problem is, FAT32 has no concept of execute ("+x") permissions. While I can launch a shell script, like so:
$ sh /path/to/fat32-usb/helloWorld.sh
, and while I can launch a simple ELF binary, like so:
$ /lib64/ld-linux-x86-64.so.2 /path/to/fat32-usb/helloWorld
, I can't seem to be able to launch the Java ELF program. I get these errors:
Error: could not find libjava.so
Error: Could not find Java SE Runtime Environment.
Before launching java, I've tried setting these environment variables as follows:
export JAVA_HOME=/path/to/fat32-usb/jre
export LD_LIBRARY_PATH="$JAVA_HOME/lib/amd64:.:$LD_LIBRARY_PATH"
export PATH="$JAVA_HOME/bin:.:$PATH"
I have also tried launching java from inside the $JAVA_HOME/bin directory. Finally, I've also tried copying all the libXXX.so's from $JAVA_HOME/lib/amd64/ to $JAVA_HOME/bin, hoping that they would get picked up from the current directory, ., somehow.
But nothing has worked.
EDIT
Here are the last few lines of strace output:
$ strace -vfo /tmp/java.strace /lib64/ld-linux-x86-64.so.2 /path/to/fat32-usb/jre ...
...
readlink("/proc/self/exe", "/lib/x86_64-linux-gnu/ld-2.17.so", 4096) = 32
write(2, "Error: could not find libjava.so", 32) = 32
write(2, "\n", 1) = 1
write(2, "Error: Could not find Java SE Ru"..., 50) = 50
write(2, "\n", 1) = 1
exit_group(2) = ?
EDIT2
And here is the output of ltrace (just a single line!):
$ ltrace -s 120 -e '*' -ifo /tmp/java.ltrace /lib64/ld-linux-x86-64.so.2 /path/to/fat32-usb/jre ...
30913 [0xffffffffffffffff] +++ exited (status 2) +++
EDIT 3
This is ltrace excerpt around loading of libjava.so by a Java on an ext4 partition (and not the problem FAT32 partition), which I can load fine:
5525 [0x7f7627600763] <... snprintf resumed> "/home/aaa/bbb/jdk1.7.0_40/lib/amd64/libjava.so", 4096, "%s/lib/%s/libjava.so", "/home/aaa/bbb/jdk1.7.0_40", "amd64") = 46
5525 [0x7f762760076d] libjli.so->access("/home/aaa/bbb/jdk1.7.0_40/lib/amd64/libjava.so", 0) = -1
5525 [0x7f762760078d] libjli.so->snprintf( <unfinished ...>
5525 [0x3085246bdb] libc.so.6->(0, 0x7fffffd8, 0x7f7627607363, 39) = 0
5525 [0x3085246be3] libc.so.6->(0, 0x7fffffd8, 0x7f7627607363, 39) = 0
5525 [0x7f762760078d] <... snprintf resumed> "/home/aaa/bbb/jdk1.7.0_40/jre/lib/amd64/libjava.so", 4096, "%s/jre/lib/%s/libjava.so", "/home/aaa/bbb/jdk1.7.0_40", "amd64") = 50
5525 [0x7f7627600797] libjli.so->access("/home/aaa/bbb/jdk1.7.0_40/jre/lib/amd64/libjava.so", 0) = 0
And this is the strace output of, again, the healthy/loading java.
5952 readlink("/proc/self/exe", "/home/aaa/bbb/jdk1.7.0_40/bin/ja"..., 4096) = 34
5952 access("/home/aaa/bbb/jdk1.7.0_40/lib/amd64/libjava.so", F_OK) = -1 ENOENT (No such file or directory)
5952 access("/home/aaa/bbb/jdk1.7.0_40/jre/lib/amd64/libjava.so", F_OK) = 0
5952 open("/home/aaa/bbb/jdk1.7.0_40/jre/lib/amd64/jvm.cfg", O_RDONLY) = 3

Autoconf test for JNI include dir

I'm working on a configuration script for a JNI wrapper. One of the configuration parameters is the path to jni.h. What's a good quick-and-dirty Autoconf test for whether this parameter is set correctly for C++ compilation? You can assume you're running on Linux and g++ is available.
Alternatively, is there a way to get javah (or a supporting tool) to give me this path directly?
Then there is the easy way: http://www.gnu.org/software/autoconf-archive/ax_jni_include_dir.html
Sometimes it is best to just use the standard recipies.
Checking for headers is easy; just use AC_CHECK_HEADER. If it's in a weird place (i.e., one the compiler doesn't know about), it's entirely reasonable to expect users to set CPPFLAGS.
The hard part is actually locating libjvm. You typically don't want to link with this; but you may want to default to a location to dlopen it from if JAVA_HOME is not set at run time.
But I don't have a better solution than requiring that JAVA_HOME be set at configure time. There's just too much variation in how this stuff is deployed across various OSes (even just Linux distributions). This is what I do:
AC_CHECK_HEADER([jni.h], [have_jni=yes])
AC_ARG_VAR([JAVA_HOME], [Java Runtime Environment (JRE) location])
AC_ARG_ENABLE([java-feature],
[AC_HELP_STRING([--disable-java-feature],
[disable Java feature])])
case $target_cpu in
x86_64) JVM_ARCH=amd64 ;;
i?86) JVM_ARCH=i386 ;;
*) JVM_ARCH=$target_cpu ;;
esac
AC_SUBST([JVM_ARCH])
AS_IF([test X$enable_java_feature != Xno],
[AS_IF([test X$have_jni != Xyes],
[AC_MSG_FAILURE([The Java Native Interface is required for Java feature.])])
AS_IF([test -z "$JAVA_HOME"],
[AC_MSG_WARN([JAVA_HOME has not been set. JAVA_HOME must be set at run time to locate libjvm.])],
[save_LDFLAGS=$LDFLAGS
LDFLAGS="-L$JAVA_HOME/lib/$JVM_ARCH/client -L$JAVA_HOME/lib/$JVM_ARCH/server $LDFLAGS"
AC_CHECK_LIB([jvm], [JNI_CreateJavaVM], [LIBS=$LIBS],
[AC_MSG_WARN([no libjvm found at JAVA_HOME])])
LDFLAGS=$save_LDFLAGS
])])
FYI - the patch below against the latest ax_jni_include_dir.m4 works for me on Macos 11.1.
--- a/m4/ax_jni_include_dir.m4
+++ b/m4/ax_jni_include_dir.m4
## -73,13 +73,19 ## fi
case "$host_os" in
darwin*) # Apple Java headers are inside the Xcode bundle.
- macos_version=$(sw_vers -productVersion | sed -n -e 's/^#<:#0-9#:>#
*.\(#<:#0-9#:>#*\).#<:#0-9#:>#*/\1/p')
- if #<:# "$macos_version" -gt "7" #:>#; then
- _JTOPDIR="$(xcrun --show-sdk-path)/System/Library/Frameworks/JavaVM.framework"
- _JINC="$_JTOPDIR/Headers"
+ major_macos_version=$(sw_vers -productVersion | sed -n -e 's/^\(#<:#0-9#:>#*\).#<:#0-9#:>#*.#<:#0-9#:>#*/\1/p')
+ if #<:# "$major_macos_version" -gt "10" #:>#; then
+ _JTOPDIR="$(/usr/libexec/java_home)"
+ _JINC="$_JTOPDIR/include"
else
- _JTOPDIR="/System/Library/Frameworks/JavaVM.framework"
- _JINC="$_JTOPDIR/Headers"
+ macos_version=$(sw_vers -productVersion | sed -n -e 's/^#<:#0-9#:>#*.\(#<:#0-9#:>#*\).#<:#0-9#:>#*/\1/p')
+ if #<:# "$macos_version" -gt "7" #:>#; then
+ _JTOPDIR="$(xcrun --show-sdk-path)/System/Library/Frameworks/JavaVM.framework"
+ _JINC="$_JTOPDIR/Headers"
+ else
+ _JTOPDIR="/System/Library/Frameworks/JavaVM.framework"
+ _JINC="$_JTOPDIR/Headers"
+ fi
fi
;;
*) _JINC="$_JTOPDIR/include";;

Categories

Resources