Protobuf: build() throws UninitializedMessageException although result is properly initialized

Created on 2 Oct 2016  路  7Comments  路  Source: protocolbuffers/protobuf

Came across this problem out of the blue today after years of usage of one and the same protocol buffer proxy class. But the environment has changed: New Google versions, gradle versions, Android studio versions etc.

This part excepts at runtime. It does not, if I step through code. My device is an Nexus 6P Android 7 (Maybe this has an impact too.)

      if (!result.isInitialized()) {
        throw newUninitializedMessageException(result);
      }

After some research I came across Patrick Linehan's analysis here https://groups.google.com/forum/#!topic/protobuf/kpZia0Rzsp8
which underlined my suspicions. His suggestion to add android:vmSafeMode to AndroidManifest.xml does not help any longer, but the other suggestion (change byte to int) does it.

I'm using Protocol Buffer 2.7.4, but looking at the current source code I'm seeing, that the strange byte/int handling is still in the proxy class template.

Please adapt.

java question

Most helpful comment

Hello,

Thanks for reporting this. Funny to see that link to Patrick - used to work with him way back when :)

Could you provide us with a small example that reproduces this issue? That will be useful to ensure that our fix actually fixes the issue. I'll also take it to the ART team to see if we can fix the underlying VM bug, if present.

Thanks!

  • D

All 7 comments

The linked analysis points to a Android VM bug. I guess we can adapt the code to workaround it before the bug in Android VM is fixed.

@nmittler @danielweis Have you guys heard of similar issues before?

Exactly. This is what I wanted to trigger. You just need to change your proxy template to use "int" instead of "byte".

Hello,

Thanks for reporting this. Funny to see that link to Patrick - used to work with him way back when :)

Could you provide us with a small example that reproduces this issue? That will be useful to ensure that our fix actually fixes the issue. I'll also take it to the ART team to see if we can fix the underlying VM bug, if present.

Thanks!

  • D

Thanks for the follow up.

Regarding the sample: Well, I could, but I doubt it would be of help. As I said: The same code worked like a champ for years. Out of the sudden it caused problems. No changes made. So I doubt you would be able to reproduce the problem, because it would with a high probability not happen on your machine.

However, I suppose, your fix is to change the "byte" to an "int" like so:

Original:
 private byte memoizedIsInitialized = -1;
  public final boolean isInitialized() {
    byte isInitialized = memoizedIsInitialized;
    if (isInitialized != -1) return isInitialized == 1;

....

Fix:
 private int memoizedIsInitialized = -1;
  public final boolean isInitialized() {
    int isInitialized = memoizedIsInitialized;
    if (isInitialized != -1) return isInitialized == 1;

This fix in fact will not cause any harm to anybody :) But it will circumvent possible problems with sign expansion. It did end the mess for me :)

That potentially increases the object size of every message so it might not be ideal.

Could you share an APK that exhibits the issue? And what device model/OS version it reproduces on? That would be enough for us to at least tackle this from the VM side.

I reproduced this issue on my Nexus 6P/Android N.

It seems to be linked to InstantRun. When I disable it, code works fine.

Upgrading Android Studio to 2.3 Beta 1 and the gradle wrapper to Gradle 3.2 as well as using classpath 'com.android.tools.build:gradle:2.3.0-beta1' and buildToolsVersion '25.0.2' in build.gradle fixed the issue for me.

Alternatively, while Android Studio 2.3 is still in beta, disable Instant Run as @mayardb has found out. :tada:

Was this page helpful?
0 / 5 - 0 ratings