OK, I've experimented with some of the ideas I had and some of the ideas suggested here, and it seems to boil down to three possible solutions for the JNI parameter lifetime issue:
1) Make the 2-arg constructor for ScopedJavaLocalRef inaccessible to most code by some mechanism (exactly which isn't important), thus banning "general" code from promoting jobject to ScopedJavaLocalRef. This is what I was talking about originally in this thread.
Then go find all the places that no longer compile (looks like there's about 60 files that do this) and either exempt them (if they're JNI helper/utility functions) or introduce new helpers to remove their need to do it (for things like array element accesses, which aren't currently wrapped but could be).
The problem with this is that the cases which are actually causing the problem (i.e. the ones where people really are wrapping JNI method parameters in ScopedJavaLocalRef) don't have any alternative in many cases because they want to pass the object to a function that takes a JavaRef, so we'd need to introduce a new type of JavaRef for them to use, a JavaParamRef that doesn't delete the reference it refers to. If JavaParamRef was misused for objects that aren't parameters it would introduce the opposite bug: objects that are held referenced longer than they should be (though local refs are all freed in any case when we return to java, so it's not a permanent leak).
2) Introduce a JavaParamRef type that works as in 1), and make the JNI generator wrap all object parameters of JNI methods in one before passing them to the actual implementations. I've prototyped this in the JNI generator and the code to do it adds yet more complexity to the already overcomplicated JNI generator, but given enough time this could probably be refactored to be somewhat less terrible.
This works pretty reasonably in theory and removes most of the cases where we ever pass bare jobjects around in chromium, but the practical problem is that there are something like 800 files containing several thousand JNI methods which would all need to be updated to have a new signature and to actually use the variables differently (calling .obj() on them to get the jobject back, or interacting with other JNI helper functions differently). This is going to be a very long and boring job that I'm not sure could be entirely automated (though some cases probably could be).
3) Just have the JNI generator make a new local ref for every parameter so we can delete them without worrying. No real changes to the actual chromium code. Adds the performance cost of calling back into the VM at least one additional time per JNI method call (every method has at least one jobject parameter: the calling object/class). Uses up more of the local reference slots allowed by the spec (though in practise the android runtime seems to dynamically allocate them anyway and there may not be a real meaningful limit).
These all seem to be pretty sucky options. Any thoughts? :)