4

I have an application in production that is receiving a significant number of force/closes when calling an authenticated Cloud Endpoint. The most telling message is " java.lang.IllegalArgumentException: Service not registered: com.google.android.gms.internal.es@4481e6a8". The logic works correctly 95% of the time. The stack trace of the failure is as follows:

java.lang.RuntimeException: An error occured while executing doInBackground() at android.os.AsyncTask$3.done(AsyncTask.java:200) at java.util.concurrent.FutureTask$Sync.innerSetException(FutureTask.java:273) at java.util.concurrent.FutureTask.setException(FutureTask.java:124) at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:307) at java.util.concurrent.FutureTask.run(FutureTask.java:137) at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1068) at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:561) at java.lang.Thread.run(Thread.java:1096)Caused by: java.lang.IllegalArgumentException: Service not registered: com.google.android.gms.internal.es@4481e6a8 at android.app.ActivityThread$PackageInfo.forgetServiceDispatcher(ActivityThread.java:1074) at android.app.ContextImpl.unbindService(ContextImpl.java:886) at android.content.ContextWrapper.unbindService(ContextWrapper.java:352) at com.google.android.gms.auth.GoogleAuthUtil.java.lang.String getToken(android.content.Context,java.lang.String,java.lang.String)(Unknown Source) at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:305) at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:305) at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:305) at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:305) at com.google.android.gms.auth.GoogleAuthUtil.java.lang.String getToken(android.content.Context,java.lang.String,java.lang.String)(Unknown Source) at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:305) at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:305) at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:305) at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:305) at com.google.api.client.googleapis.extensions.android.gms.auth.GoogleAccountCredential.java.lang.String getToken()(SourceFile:192) at com.google.api.client.googleapis.extensions.android.gms.auth.GoogleAccountCredential$RequestHandler.void intercept(com.google.api.client.http.HttpRequest)(SourceFile:217) at com.google.api.client.http.HttpRequest.com.google.api.client.http.HttpResponse execute()(SourceFile:836) at com.google.api.client.googleapis.services.AbstractGoogleClientRequest.com.google.api.client.http.HttpResponse executeUnparsed(boolean)(SourceFile:412) at com.google.api.client.googleapis.services.AbstractGoogleClientRequest.com.google.api.client.http.HttpResponse executeUnparsed()(SourceFile:345) at com.google.api.client.googleapis.services.AbstractGoogleClientRequest.java.lang.Object execute()(SourceFile:463) at com.jdub.empiretracker.EmpireTrackerActivity$QueryMarketStats.com.google.api.services.marketendpoint.model.Market doInBackground(com.google.api.services.marketendpoint.model.Market[])(SourceFile:355) at com.jdub.empiretracker.EmpireTrackerActivity$QueryMarketStats.java.lang.Object doInBackground(java.lang.Object[])(SourceFile:1) at android.os.AsyncTask$2.call(AsyncTask.java:185) at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:305) ... 4 more

My implementation is very consistent with the Google samples. For example, my Android activity is using an AsyncTask to make the call, as follows:

    private class QueryMarketStats extends AsyncTask<com.google.api.services.marketendpoint.model.Market, com.google.api.services.marketendpoint.model.Market, com.google.api.services.marketendpoint.model.Market> {

    /* (non-Javadoc)
     * @see android.os.AsyncTask#doInBackground(Params[])
     */
    @Override
    protected com.google.api.services.marketendpoint.model.Market doInBackground(com.google.api.services.marketendpoint.model.Market...markets) {

        com.google.api.services.marketendpoint.model.Market result = null;

        try {
            result = service.market().latest(state.getServerID()).execute();
        }
        catch (SSLException e) {
            PrimeDataStore();
            Log.d("app", e.getMessage(), e);
        }
        catch (GoogleAuthIOException e) {
            Log.d("app", e.getMessage(), e);
        }
        catch (IOException e) {
            Log.d("app", e.getMessage(), e);
        }

        return result;
    }

    /* (non-Javadoc)
     * @see android.os.AsyncTask#onPostExecute(java.lang.Object)
     */
    @Override
    protected void onPostExecute(com.google.api.services.marketendpoint.model.Market result) {

        // Process result...
    }

}

The line giving the error is: result = service.market().latest(state.getServerID()).execute();

I have verified the parameter for getServerID() is returning a value that is acceptable. My theory at this point is that Google Play Services is not able to provide an account that is still authenticated. Although I have been unable to reproduce, I believe the issue may occur when the application goes to sleep. I therefore confirmed my onResume() logic, as follows:

    @Override
protected void onResume() {
    super.onResume();
    checkPlayServices();
    isInFront = true;
}

What else could cause this intermittent failure? Is this a known issue?

jdub
  • 133
  • 8

1 Answers1

2

In lieu of a better alternative, I am catching the exception and triggering a retry with success. Whatever intermittent issue is causing the service not to be registered at the point in time the endpoint is called, future invocations of the service work properly.

Work-around Code

@Override
protected com.google.api.services.marketendpoint.model.Market doInBackground(com.google.api.services.marketendpoint.model.Market...markets) {

    com.google.api.services.marketendpoint.model.Market result = null;

    try {
        result = service.market().latest(state.getServerID()).execute();
    }
    catch (SSLException e) {
        PrimeDataStore();
        Log(e);
    }
    catch (GoogleAuthIOException e) {
        Log(e);
    }
    catch (IOException e) {
        Log(e);
    }
    catch (IllegalArgumentException e) {
        // This caused a lot of intermittent force/closes.
        Log(e);
    }

    return result;
}

@Override
protected void onPostExecute(com.google.api.services.marketendpoint.model.Market result) {

    DismissProgressDialogIfPresent();

    com.google.api.services.marketendpoint.model.Market m = (com.google.api.services.marketendpoint.model.Market) result;

    if( m == null)
    {
        // Verify the current activity is active
        if( isInFront ) {

            // Present a retry/cancel dialog
            AlertDialog.Builder builder = new AlertDialog.Builder(EmpireTrackerActivity.this);
            builder.setMessage("An error was encountered retrieving the latest market data.\n\nPlease verify you are connected to the Internet.");
            builder.setPositiveButton("Retry", new DialogInterface.OnClickListener() {
                public void onClick(DialogInterface dialog, int which) {
                    dialog.dismiss();

                    m_ProgressDlg = ProgressDialog.show(EmpireTrackerActivity.this, "Please wait...", "Retrieving data ...", true);
                    new QueryMarketStats().execute();
                }
            });
            builder.setNegativeButton("Cancel", new DialogInterface.OnClickListener() {
                public void onClick(DialogInterface dialog, int which) {

                    dialog.dismiss();
                }
            });
            AlertDialog alert = builder.create();
            alert.show();
        }

        return;
    }

    // Process newly posted data            
    state.setMarketObj(m);
    state.setIsInitialized(true);
    state.WriteFile(EmpireTrackerActivity.this);

    super.onPostExecute(result);
}       

}

jdub
  • 133
  • 8