Je pense que je vois la source de votre confusion. Dalvik VM n'est pas une machine virtuelle au même titre que VMware ou Virtualbox. Dans ce type de VM, VMware (ou autre) prétend être l'ordinateur complet. Chaque opération doit passer par la VM, elle doit être empêchée d'accéder au matériel réel, et si elle accède au matériel réel, VMware doit faire un certain travail pour prétendre être le matériel réel, donner le résultat au système d'exploitation, et faire en sorte que le système d'exploitation donne le résultat à l'application. Il y a une copie complète du système d'exploitation qui tourne à l'intérieur de la VM, donc c'est une application, sur un système d'exploitation, sur VMware, qui est lui-même une application tournant sur un système d'exploitation, qui est ensuite sur le matériel réel.
Java et (par extension) Dalvik VM ne sont pas comme ça. Il s'agit plutôt d'une abstraction de la vraie machine. Le matériel réel n'est pas caché à l'application, et il n'y a pas de copie supplémentaire du système d'exploitation.
Une application Java est juste un processus sur le téléphone comme une application non-Java. Lorsqu'une application Java fait un appel de fonction via JNI, Dalvik doit effectuer un peu de comptabilité pour transmettre les objets utilisés dans l'appel de fonction au code natif, puis le code natif s'exécute simplement dans le processus, sans aucune VM impliquée. Ensuite, il y a encore un peu de comptabilité pour renvoyer le résultat au code Java.
Le code dans l'appel JNI est aussi rapide que n'importe quel code natif dans un processus où il n'y a pas de Java du tout. La seule surcharge est la comptabilisation de l'entrée et de la sortie de l'appel.