Measure Twice, Byte Once Making Stuff

19Jan/120

Android NativeActivity JNI and ClassNotFoundException

We're working on some code related to the Android NDK and using JNI to call Java methods from C/C++. This site has some great code + explanation on how to access your custom Java classes. If you still get ClassNotFoundExceptions after implementing that code, and you've tried everything you can think of, double-check your AndroidManifest.xml for the application attribute android:hasCode="false".

Some of the NDK samples include this setting, which will cause your Java code to be left out of the final APK.

14Jan/120

Fixing ProGuard Warning “can’t write resource [META-INF/MANIFEST.MF]“

We're using ProGuard in our Android build and were getting a number of warnings regarding duplicate entries in the output jar. When ProGuard encounters resources in an input jar, it will by default copy the resources into the output jar. This is fine as long as you don't have multiple jars that contain resources with the same name. All jars(that I'm aware of) have manifest files, so attempting to use ProGuard with multiple input jars will cause warnings that look like: "Warning: can't write resource [META-INF/MANIFEST.MF] (Duplicate zip entry [yyy.jar:META-INF/MANIFEST.MF])".

The warnings are harmless, but a clean build is a happy build, so we might as well try and get rid of them. The ProGuard Manual actually describes what needs to be done, but it only provides a solution for the case where input jars are specified individually:

-injars in1.jar
-injars in2.jar(!META-INF/MANIFEST.MF)
-injars in3.jar(!META-INF/MANIFEST.MF)
view raw gistfile1.txt This Gist brought to you by GitHub.

When using ProGuard in the Android build process, the default behavior is to pass in all input jars in a giant delimited(semi-colon on Windows) blob. I have done some experimentation, but was unable to determine how an input filter can be used when multiple jars(having absolute paths) are passed in this way. Fortunately, it's not too difficult to change the build process to pass in a list of input jars individually and with individual filters.

This is the relevant section of the standard Android build.xml(starting around line 700):

<!-- Build a path object with all the jar files that must be obfuscated.
This include the project compiled source code and any 3rd party jar
files. -->
<path id="project.jars.ref">
<pathelement location="${preobfuscate.jar.file}" />
<path refid="jar.libs.ref" />
</path>
<!-- Set the project jar files Path object into a single property. It'll be
all the jar files separated by a platform path-separator.
Each path must be quoted if it contains spaces.
-->
<pathconvert property="project.jars" refid="project.jars.ref">
<firstmatchmapper>
<regexpmapper from='^([^ ]*)( .*)$$' to='"\1\2"'/>
<identitymapper/>
</firstmatchmapper>
</pathconvert>

<mkdir dir="${obfuscate.absolute.dir}" />
<delete file="${preobfuscate.jar.file}"/>
<delete file="${obfuscated.jar.file}"/>
<jar basedir="${out.classes.absolute.dir}"
destfile="${preobfuscate.jar.file}" />
<proguard>
@${proguard.config}
-injars ${project.jars}
-outjars "${obfuscated.jar.file}"
-libraryjars ${android.libraryjars}
-dump "${obfuscate.absolute.dir}/dump.txt"
-printseeds "${obfuscate.absolute.dir}/seeds.txt"
-printusage "${obfuscate.absolute.dir}/usage.txt"
-printmapping "${obfuscate.absolute.dir}/mapping.txt"
</proguard>

view raw gistfile1.xml This Gist brought to you by GitHub.

The directives above create a new object that combines the location of the compiled jar along with other jars that were used during compilation. These locations are then joined into a string by the pathconvert task, which also does some transformation to ensure that paths containing spaces are quoted properly. Finally, the string from pathconvert(stored in project.jars) is passed into proguard via the statement: "-injars ${project.jars}"

This is the same section of my updated build.xml:

<!-- Set the project jar files Path object into a single property. It'll be
all the jar files separated by a platform path-separator.
Each path must be quoted if it contains spaces.
-->
<pathconvert property="project.jars" refid="jar.libs.ref" pathsep=" ">
<firstmatchmapper>
<regexpmapper from='^([^ ]*)( .*)$$' to='-injars "\1\2"(!META-INF/MANIFEST.MF)'/>
<regexpmapper from='(.*)' to='-injars \1(!META-INF/MANIFEST.MF)'/>
</firstmatchmapper>
</pathconvert>

<mkdir dir="${obfuscate.absolute.dir}" />
<delete file="${preobfuscate.jar.file}"/>
<delete file="${obfuscated.jar.file}"/>
<jar basedir="${out.classes.absolute.dir}"
destfile="${preobfuscate.jar.file}" />
<proguard>
@${proguard.config}
-injars ${preobfuscate.jar.file}
${project.jars}
-outjars "${obfuscated.jar.file}"
-libraryjars ${android.libraryjars}
-dump "${obfuscate.absolute.dir}/dump.txt"
-printseeds "${obfuscate.absolute.dir}/seeds.txt"
-printusage "${obfuscate.absolute.dir}/usage.txt"
-printmapping "${obfuscate.absolute.dir}/mapping.txt"
</proguard>

view raw gistfile1.xml This Gist brought to you by GitHub.

The goal of my changes is to preserve the manifest files from the original jar("preobfuscate.jar.file") and ignore(filter) the manifest files from the remaining input jar files. Since I haven't figured out how to filter input jars when passed in as a blob, I instead use the pathconvert task to transform each input jar location into a separate "-injars" statement with its own manifest filter. The property containing these locations is then passed into ProGuard directly via: "${project.jars}"

The solution isn't as clean as I would have liked, but it does fix the warnings.

17Jul/110

Implicit vs Explicit Returns in Ruby

Ruby supports implicit returns, i.e., the value of the last expression in a block/statement is what will be returned.  One might assume that  implicit returns and explicit returns(e.g. "return 123") are functionally equivalent.  Although this is often the case, there is a gotcha scenario when using an explicit return within a block.  In the following Gist, an explicit return is used within a map block.  The result is that explicitReturn() will end up returning a single upper-case string("PANGOLIN"), rather than an array of upper-case strings.

# Simple demonstration of an 'implicit' return
def implicitReturn()
  "implicit return\n"
end

# Simple demonstration of an 'explicit' return. Using an explicit return,
# even within a block, will exit the function.
def explicitReturn()
  examples = ["pangolin", "cat", "macgyver"]

  largerExamples = examples.map { |item|
    # Explicit return will return the first item in uppercase, rather than
    # allowing us to map our array
    return item.upcase
  }

  #This line will not be executed
  largerExamples
end

print implicitReturn() # Output: implicit return
print explicitReturn() # Output: PANGOLIN

view raw returns.rb This Gist brought to you by GitHub.

On a semi-related note, Martin Hsu provided my Pangolin inspiration: http://www.martinhsu.com/pangolin-rider-p-50.html

Filed under: Coding, Gotchas, Ruby No Comments
2Jan/111

Fractal Rendering

I had some vacation time recently and wanted to explore HTML5/Canvas and fractals, so I wrote a basic JavaScript-based Mandelbrot renderer. The code is available in my GitHub repository, and the demo page is here. It takes about 10-15 seconds to render a single scene. This would be a good application for parallelization, but there's generally only a single thread available to JavaScript within the browser. Perhaps there's an opportunity to add support for HTML5 worker threads here.

19Dec/100

printf(“Hello world!”);

Time to start putting some new information on this site.  Expect something useful within the next few weeks.  Old content is still available at /old

Filed under: Uncategorized No Comments