Why does Google's Fido2PendingIntent().launchPendingIntent method fail (no fingerprint/passcode prompt is displayed) on the first attempt with the error code:
SECURITY_ERR - The operation is insecure. The incoming request cannot be validated.
And, successive attempts typically result in the the above call working (fingerprint/passcode is prompt displayed), and no longer getting this error.
These are the main snippets of the code:
ListenerRegistration.java:
try {
// Get intent for FIDO2 operation.
Fido2ApiClient fido2ApiClient = Fido.getFido2ApiClient( this.activity );
Task<Fido2PendingIntent> task = fido2ApiClient.getRegisterIntent( pkcco );
// Send intent back to UI through callback.
Log.d( TAG, "LISTENERREGISTRATION.java IS NOW ATTEMPTING TO OPEN FINGERPRINT/SECRUITY PROMPT" );
this.fidoDelegate.launchFidoPrompt( Tasks.await( task ), FidoPromptCallback.FIDO2_REGISTRATION );
// Wait for authenticator to complete.
this.fidoAuthenticatorLock.acquire();
} catch( ExecutionException e ) {
// Threw exception while waiting for authenticator.
// Pass Fido2AuthenticatorException back to calling class so it can handle error appropriately.
throw new Fido2AuthenticatorException( this.sFido2AuthenticatorErrorMessage, this.fido2ErrorCode );
} catch( InterruptedException e ) {
// Threw exception while waiting for authenticator.
// Pass Fido2AuthenticatorException back to calling class so it can handle error appropriately.
throw new Fido2AuthenticatorException( this.sFido2AuthenticatorErrorMessage, this.fido2ErrorCode );
}
MainActivity.java:
// Instantiate class to handle VC functionality called by listener.
this.lo = new ListenerOperations(MainActivity.this, new FidoPromptCallback() {
#Override
public void launchFidoPrompt(Fido2PendingIntent fido2Intent, int iOperation) {
// Determine how to handle authenticator result.
int iCode;
if (iOperation == FidoPromptCallback.FIDO2_REGISTRATION) {
iCode = MainActivity.REQUEST_FIDO2_REGISTER;
} else if (iOperation == FidoPromptCallback.FIDO2_ASSERTION) {
iCode = MainActivity.REQUEST_FIDO2_ASSERTION;
} else {
// Invalid operation.
iCode = -1;
}
try {
// Launch the fingerprint dialog by launching the intent from FIDO2 API.
Log.d( TAG, "MAINACTIVITY.java IS NOW ATTEMPTING TO OPEN FINGERPRINT/SECRUITY PROMPT" );
fido2Intent.launchPendingIntent( MainActivity.this, iCode );
Log.d( TAG, "MAINACTIVITY.java HAS OPENNED FINGERPRINT/SECRUITY PROMPT WITH NO ERRORS" );
} catch( IntentSender.SendIntentException e ) {
// Error launching pending intent for register request.
Log.d(TAG, "SADFACE - FAILED TO OPEN FINGERPRINT FIDO DIALOG");
} catch (Exception e) {
Log.d( TAG, "GENERAL EXCEPTION OCCURRED WHEN CALLING fido2Intent.launchPendingIntent" );
e.printStackTrace();
}
Log.d( TAG, "MAINACTIVITY.java END OF launchFidoPrompt()" );
}
On failure (and success) the logs look like this (because no exception is ever thrown even after getting the SECURITY_ERR error):
other logs
...
10-01 10:31:36.289 14272 15728 D MainActivity.java: LISTENERREGISTRATION.java IS NOW ATTEMPTING TO OPEN FINGERPRINT/SECRUITY PROMPT
...
10-01 10:31:37.589 14974 15728 D MainActivity.java: MAINACTIVITY.java IS NOW ATTEMPTING TO OPEN FINGERPRINT/SECRUITY PROMPT
10-01 10:31:37.602 4053 4953 I ActivityManager: START u0 {act=null typ=null flg=0x0 cmp=ComponentInfo{com.google.android.gms/com.google.android.gms.fido.fido2.ui.Fido2FullScreenActivity}} from uid 10031
10-01 10:31:37.623 4053 4953 D CustomFrequencyManagerService: acquireDVFSLockLocked : type : DVFS_MIN_LIMIT frequency : 1560000 uid : 1000 pid : 4053 pkgName : AMS_APP_SWITCH#CPU_MIN#47
10-01 10:31:37.625 4053 4953 D ActivityManagerPerformance: AMP_acquire() APP_SWITCH
10-01 10:31:37.628 3633 3633 I SurfaceFlinger: id=56380 createSurf (3040x3040),2 flag=4, AppWindowToken{2800ead token=Token{77b3fc4 ActivityRecord{44bad7 u0 com.google.android.gms/.fido.fido2.ui.Fido2FullScreenActivity t7062}}}#0
10-01 10:31:37.636 4053 4953 D ActivityManager: Received ACTIVITY intent in key u0 {bcd25e2 act=nullstartActivity cmp=ComponentInfo{com.google.android.gms/com.google.android.gms.fido.fido2.ui.Fido2FullScreenActivity} res=0} from uid 10218
10-01 10:31:37.637 14974 15728 D MainActivity.java: MAINACTIVITY.java HAS OPENNED FINGERPRINT/SECRUITY PROMPT WITH NO ERRORS
10-01 10:31:37.637 14974 15728 D MainActivity.java: MAINACTIVITY.java END OF launchFidoPrompt()
The fact that my code does not get notified of any exceptions, leads me to believe that the issue lies inside the call to Fido2PendingIntent().launchPendingIntent.
Note that now exceptgion in this code:
Related
Recently I sometimes got this exception when MainActivity called onResume().
java.lang.RuntimeException: Unable to resume activity {com.qau4d.c35s3.androidapp/com.xxx.XXX.XXX.MainActivity}: java.lang.IllegalArgumentException
at android.app.ActivityThread.performResumeActivity(ActivityThread.java:3400)
at android.app.ActivityThread.handleResumeActivity(ActivityThread.java:3440)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1510)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loop(Looper.java:154)
at android.app.ActivityThread.main(ActivityThread.java:6077)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:865)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:755)
Caused by: java.lang.IllegalArgumentException
at android.os.Parcel.readException(Parcel.java:1687)
at android.os.Parcel.readException(Parcel.java:1636)
at android.app.ActivityManagerProxy.isTopOfTask(ActivityManagerNative.java:5475)
at android.app.Activity.isTopOfTask(Activity.java:5961)
at android.app.Activity.onResume(Activity.java:1252)
at com.qau4d.c35s3.androidapp.onResume(XActivity.java:29)
at com.qau4d.c35s3.androidapp.onResume(MainActivity.java:196)
at android.app.Instrumentation.callActivityOnResume(Instrumentation.java:1269)
at android.app.Activity.performResume(Activity.java:6768)
at android.app.ActivityThread.performResumeActivity(ActivityThread.java:3377)
Both in MainActivity and super class XActivity, only super.onResume(); is called. It's really strange to get this exception after a long time normal development.I checked some relative reference material but nothing got.
In the method Activity#isTopOfTask we can see:
private boolean isTopOfTask() {
if (mToken == null || mWindow == null) {
return false;
}
try {
return ActivityManager.getService().isTopOfTask(getActivityToken());
} catch (RemoteException e) {
return false;
}
}
And in ActivityManagerService#isTopOfTask we can found:
#Override
public boolean isTopOfTask(IBinder token) {
synchronized (this) {
ActivityRecord r = ActivityRecord.isInStackLocked(token);
if (r == null) {
throw new IllegalArgumentException();
}
return r.task.getTopActivity() == r;
}
}
So, I think that ActivityRecord is null.But I don't know why it is null....
There is insufficient information in your question to determine the cause of the java.lang.IllegalArgumentException, Unfortunately the android ActivityThread doesn't log the stacktrace of that exception, and the exception message appears to be empty.
However, it looks like there is a way forward. The exception is handled by the following code in the ActivityThread::performResumeActivity method:
} catch (Exception e) {
if (!mInstrumentation.onException(r.activity, e)) {
throw new RuntimeException(
"Unable to resume activity "
+ r.intent.getComponent().toShortString()
+ ": " + e.toString(), e);
}
}
If you register an Instrumentation class for your activity, it should be possible to use an onException method to log the stacktrace for the causal exception. Another possibility is to use Thread.setUncaughtExceptionHandler to set a handler for the thread in which the IllegalArgumentException is thrown.
These won't solve the problem (!) but it will get you a step closer to a solution.
I want the user to be able to send an error report when my service crashes. I have an GUI app which gets updated using broadcasts from the service. The service runs in a different process and runs as foreground. I used the same code to attach the default exception handler to my GUI and there it works fine (opens the e-mail send app and the body of the e-mail contains the exception). But for my service threads, I cannot get them to call the UncaughtExceptionHandler.
The research I did so far is that the thread that crashes has a different threadid (12) than the thread I registered the cutom exceptionhandler on (229) The registration and the crash are in the same Timer_Tick runnable and should have the same threadid.
Logcat output:
> D/Registratie: General exception handler set for threadid=229
> D/Registratie: ThreadName in Timer_Tick: Timer-0 threadId=229
> D/Registratie: ThreadName in Timer_Tick: Timer-0 threadId=229
> D/Registratie: ThreadName in Timer_Tick: Timer-0 threadId=229
> D/Registratie: Throw ArrayIndexOutOfBounds exception W/dalvikvm:
> threadid=12: thread exiting with uncaught exception (group=0x4169fba8)
Service member and method:
// declared non-anonymous to prevent the garbage collector erroneously clearing
private Thread.UncaughtExceptionHandler mUEHandler;
public void attachGeneralExceptionHandler(){
mUEHandler = new Thread.UncaughtExceptionHandler() {
#Override
public void uncaughtException(Thread t, Throwable e) {
Log.d(TAG, "Custom crash handler: build crashrapport and intent");
sendExceptionReport(t,e);
mUEHandler.uncaughtException(t, e);
}
};
Thread.setDefaultUncaughtExceptionHandler(mUEHandler);
Log.d(TAG, "General exception handler set for ThreadName: " + Thread.currentThread().getName() + " threadid=" + Thread.currentThread().getId());
}
TimerTick from the service:
private Runnable Timer_Tick = new Runnable() {
public void run() {
if(!uncaughtExceptionHandlerSet) {
// Make sure the exception handler is connected to this Timer_Tick thread
attachGeneralExceptionHandler();
uncaughtExceptionHandlerSet=true;
}
Log.d(TAG, "ThreadName in Timer_Tick: "+ Thread.currentThread().getName()+" threadId="+Thread.currentThread().getId());
if(testExceptionHandling){
Log.d("TAG", "Throw ArrayIndexOutOfBounds exception");
int[] exceptionTest = new int[3];
exceptionTest[3] = -1; // throws exception on thread with threadid 12, only one line in logcat
}
}
The documentation for Thread.setDefaultUncaughtExceptionHandler() indicates:
This handler is invoked in case any Thread dies due to an
unhandled exception
You don't need to call that method for each thread. Try setting the default handle in the onCreate() method of your service.
UPDATED:
Ok, after a few days of testing and debugging... I GOT IT TO WORK, but not the way I want.
The reason it crashed previously was because of "reorientation" of the camera during lockscreen, apparently, that crashes often.
Once I forced it to use landscape mode, it works. However, I don't want it to use landscape mode; I want it to work in portrait mode.
The code is taken directly from Android Studio's sample (Media -> MediaRecorder). The sample had the code working in landscape mode, and I can't figure how to get it to use portrait mode so I can avoid re-orientation and thus avoid the crashes?
There's nothing in the onPause, onResume code and the stacktrace pointed toward this method being called.
Easy Reproduce:
1) Use Android Studio to get the MediaRecord Sample app
2) In the manifest, change, android:screenOrientation="landscape"> to Portrait.
3) The App won't launch now.
I added mCamera.setDisplayOrientation(90), same issue.
Code:
#TargetApi(Build.VERSION_CODES.HONEYCOMB)
private boolean prepareVideoRecorder(){
// BEGIN_INCLUDE (configure_preview)
mCamera = CameraHelper.getDefaultCameraInstance();
// We need to make sure that our preview and recording video size are supported by the
// camera. Query camera to find all the sizes and choose the optimal size given the
// dimensions of our preview surface.
Camera.Parameters parameters = mCamera.getParameters();
List<Camera.Size> mSupportedPreviewSizes = parameters.getSupportedPreviewSizes();
Camera.Size optimalSize = CameraHelper.getOptimalPreviewSize(mSupportedPreviewSizes,
mPreview.getWidth(), mPreview.getHeight());
// Use the same size for recording profile.
CamcorderProfile profile = CamcorderProfile.get(CamcorderProfile.QUALITY_HIGH);
profile.videoFrameWidth = optimalSize.width;
profile.videoFrameHeight = optimalSize.height;
// likewise for the camera object itself.
parameters.setPreviewSize(profile.videoFrameWidth, profile.videoFrameHeight);
mCamera.setParameters(parameters);
try {
// Requires API level 11+, For backward compatibility use {#link setPreviewDisplay}
// with {#link SurfaceView}
mCamera.setPreviewTexture(mPreview.getSurfaceTexture());
} catch (IOException e) {
Log.e(TAG, "Surface texture is unavailable or unsuitable" + e.getMessage());
return false;
}
// END_INCLUDE (configure_preview)
// BEGIN_INCLUDE (configure_media_recorder)
mMediaRecorder = new MediaRecorder();
// Step 1: Unlock and set camera to MediaRecorder
mCamera.unlock();
mMediaRecorder.setCamera(mCamera);
// Step 2: Set sources
mMediaRecorder.setAudioSource(MediaRecorder.AudioSource.DEFAULT);
mMediaRecorder.setVideoSource(MediaRecorder.VideoSource.CAMERA);
// Step 3: Set a CamcorderProfile (requires API Level 8 or higher)
mMediaRecorder.setProfile(profile);
// Step 4: Set output file
mMediaRecorder.setOutputFile(CameraHelper.getOutputMediaFile(
CameraHelper.MEDIA_TYPE_VIDEO).toString());
mMediaRecorder.setOrientationHint(90);
// END_INCLUDE (configure_media_recorder)
MediaScannerConnection.scanFile(this, new String[] { CameraHelper.getOutputMediaFile(
CameraHelper.MEDIA_TYPE_VIDEO).getPath() }, new String[] { "video/mp4" }, null);
// Step 5: Prepare configured MediaRecorder
try {
mMediaRecorder.prepare();
} catch (IllegalStateException e) {
Log.d(TAG, "IllegalStateException preparing MediaRecorder: " + e.getMessage());
releaseMediaRecorder();
return false;
} catch (IOException e) {
Log.d(TAG, "IOException preparing MediaRecorder: " + e.getMessage());
releaseMediaRecorder();
return false;
}
return true;
}
Logs:
06-27 02:18:08.244 25734-25752/com.watchdawg.watchdawg E/MediaRecorder﹕ start failed: -22
06-27 02:18:08.253 25734-25752/com.watchdawg.watchdawg E/AndroidRuntime﹕ FATAL EXCEPTION: AsyncTask #1
Process: com.watchdawg.watchdawg, PID: 25734
java.lang.RuntimeException: An error occured while executing doInBackground()
at android.os.AsyncTask$3.done(AsyncTask.java:304)
at java.util.concurrent.FutureTask.finishCompletion(FutureTask.java:355)
at java.util.concurrent.FutureTask.setException(FutureTask.java:222)
at java.util.concurrent.FutureTask.run(FutureTask.java:242)
at android.os.AsyncTask$SerialExecutor$1.run(AsyncTask.java:231)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1112)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:587)
at java.lang.Thread.run(Thread.java:818)
Caused by: java.lang.RuntimeException: start failed.
at android.media.MediaRecorder.start(Native Method)
at com.watchdawg.watchdawg.RecordActivity$MediaPrepareTask.doInBackground(RecordActivity.java:276)
at com.watchdawg.watchdawg.RecordActivity$MediaPrepareTask.doInBackground(RecordActivity.java:267)
at android.os.AsyncTask$2.call(AsyncTask.java:292)
at java.util.concurrent.FutureTask.run(FutureTask.java:237)
at android.os.AsyncTask$SerialExecutor$1.run(AsyncTask.java:231)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1112)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:587)
at java.lang.Thread.run(Thread.java:818)
Whenever the application is removed from the recent task list, process will not be cleaned up completely, it is just that the UI will be cleaned up. So it is app responsibility to cleanup the resource held by your activity or app. Hence, you need to override onTaskRemoved() method in your service(Android service) component and perform cleanup(releasing mediaplayer instance etc).
try this way:
mMediaRecorder.setOutputFormat(MediaRecorder.OutputFormat.MPEG_4);
mMediaRecorder.setVideoFrameRate(24);
mMediaRecorder.setVideoSize(720,480);
mMediaRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB);
mMediaRecorder.setVideoEncoder(MediaRecorder.VideoEncoder.H264);
mPreview.setRotation(90);
instead of mMediaRecorder.setProfile(profile);
hope it works!
When I close my application, the service that had been started is supposed to continue running in the background. For some reason, the application crashes and throws a NullPointerException upon closing it.
I am using a MQTTConstants class to keep all the Constants in one place, and within that class I have a Hashset declared, which is then modified throughout the life of the application.
Is it possible that by closing the app, this information is being cleared? Although the service is never disconnected.
The service would continue to work off of this TOPIC_SET as it continues to run in the background.
public static HashSet<String> TOPIC_SET = new HashSet<String>();
STACK TRACE
02-20 14:14:30.620: E/AndroidRuntime(14753): FATAL EXCEPTION:
MQTTservice 02-20 14:14:30.620: E/AndroidRuntime(14753): Process:
com.l.ltestmqtt, PID: 14753 02-20 14:14:30.620:
E/AndroidRuntime(14753): java.lang.NullPointerException 02-20
14:14:30.620: E/AndroidRuntime(14753): at
com.l.ltestmqtt.MQTTService.handleStartAction(MQTTService.java:315)
02-20 14:14:30.620: E/AndroidRuntime(14753): at
com.l.ltestmqtt.MQTTService.handleStart(MQTTService.java:231)
02-20 14:14:30.620: E/AndroidRuntime(14753): at
com.l.ltestmqtt.MQTTService$2.run(MQTTService.java:196)
02-20 14:14:30.620: E/AndroidRuntime(14753): at
java.lang.Thread.run(Thread.java:841)
Here are the methods that are named within the Stack Trace
handleStart
synchronized void handleStart(Intent intent, int startId) {
// before we start - check for a couple of reasons why we should stop
Log.e("SERVICE", "----------HANDLESTART()-----------");
if (mqttClient == null) {
// we were unable to define the MQTT client connection, so we stop
// immediately - there is nothing that we can do
stopSelf();
return;
}
ConnectivityManager cm = (ConnectivityManager) getSystemService(CONNECTIVITY_SERVICE);
if (cm.getBackgroundDataSetting() == false) // respect the user's request not to use data!
{
// user has disabled background data
connectionStatus = MQTTConnectionStatus.NOTCONNECTED_DATADISABLED;
// update the app to show that the connection has been disabled
broadcastServiceStatus("Not connected - background data disabled");
// we have a listener running that will notify us when this
// preference changes, and will call handleStart again when it
// is - letting us pick up where we leave off now
return;
}
if (!handleStartAction(intent)) {
// the Activity UI has started the MQTT service - this may be starting
// the Service new for the first time, or after the Service has been
// running for some time (multiple calls to startService don't start
// multiple Services, but it does call this method multiple times)
// if we have been running already, we re-send any stored data
rebroadcastStatus();
rebroadcastReceivedMessages();
}
// if the Service was already running and we're already connected - we
// don't need to do anything
if (isAlreadyConnected() == false) {
// set the status to show we're trying to connect
connectionStatus = MQTTConnectionStatus.CONNECTING;
// we are creating a background service that will run forever until
// the user explicity stops it. so - in case they start needing
// to save battery life - we should ensure that they don't forget
// we're running, by leaving an ongoing notification in the status
// bar while we are running
NotificationManager nm = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
Notification notification =
new Notification(R.drawable.ic_launcher, "MQTT", System.currentTimeMillis());
notification.flags |= Notification.FLAG_ONGOING_EVENT;
notification.flags |= Notification.FLAG_NO_CLEAR;
Intent notificationIntent = new Intent(this, MQTTNotifier.class);
PendingIntent contentIntent =
PendingIntent.getActivity(this, 0, notificationIntent, PendingIntent.FLAG_UPDATE_CURRENT);
notification.setLatestEventInfo(this, "MQTT", "MQTT Service is running", contentIntent);
nm.notify(MQTTConstants.MQTT_NOTIFICATION_ONGOING, notification);
// before we attempt to connect - we check if the phone has a
// working data connection
if (isOnline()) {
// we think we have an Internet connection, so try to connect
// to the message broker
if (connectToBroker()) {
// we subscribe to a topic - registering to receive push
// notifications with a particular key
// in a 'real' app, you might want to subscribe to multiple
// topics - I'm just subscribing to one as an example
// note that this topicName could include a wildcard, so
// even just with one subscription, we could receive
// messages for multiple topics
//subscribe to initial TOPIC_SET topics, ie device_id_topic, all_topic
subscribeToAllTopics();
//subscribeToTopic(topicName);
}
} else {
// we can't do anything now because we don't have a working
// data connection
connectionStatus = MQTTConnectionStatus.NOTCONNECTED_WAITINGFORINTERNET;
// inform the app that we are not connected
broadcastServiceStatus("Waiting for network connection");
}
}
// changes to the phone's network - such as bouncing between WiFi
// and mobile data networks - can break the MQTT connection
// the MQTT connectionLost can be a bit slow to notice, so we use
// Android's inbuilt notification system to be informed of0
// network changes - so we can reconnect immediately, without
// having to wait for the MQTT timeout
if (netConnReceiver == null) {
netConnReceiver = new NetworkConnectionIntentReceiver();
registerReceiver(netConnReceiver, new IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION));
}
// creates the intents that are used to wake up the phone when it is
// time to ping the server
if (pingSender == null) {
pingSender = new PingSender();
registerReceiver(pingSender, new IntentFilter(MQTTConstants.MQTT_PING_ACTION));
}
}
handleStartAction
private boolean handleStartAction(Intent intent) {
String action = intent.getAction();
if (action == null) {
return false;
}
if (action.equalsIgnoreCase(MQTTConstants.MQTT_SUBSCRIBE_TOPIC_INTENT)) {
handleSubscribeTopicIntent(intent);
}
if (action.equalsIgnoreCase(MQTTConstants.MQTT_PUBLISH_MSG_INTENT)) {
handlePublishMessageIntent(intent);
}
if (action.equalsIgnoreCase(MQTTConstants.MQTT_UNSUBSCRIBE_TOPIC_INTENT)) {
handleUnsubscribeTopicIntent(intent);
}
return true;
}
UPDATES: The problem exists within the handleStart() method. If I comment this if (!handleStartAction(intent)) { the issue no longer occurs.
FOR ρяσѕρєя K
The service is started inside MQTTNotifier Activity using this
MQTTServiceDelegate.startService(this);
which references this method inside the MQTTServiceDelegateClass
public static void startService(Context context) {
Intent svc = new Intent(context, MQTTService.class);
context.startService(svc);
}
I have solved the issue, I will mark this as the answer unless someone is able to provide a better solution.
I ran a quick test to see if the intent was == null, and if it was I just logged it, otherwise I processed the code.
private boolean handleStartAction(Intent intent) {
if (intent == null) {
Log.e("NULL INTENT", "***************NULL INTENT**************");
} else {
String action = intent.getAction();
if (action == null) {
return false;
}
if (action.equalsIgnoreCase(MQTTConstants.MQTT_SUBSCRIBE_TOPIC_INTENT)) {
handleSubscribeTopicIntent(intent);
}
if (action.equalsIgnoreCase(MQTTConstants.MQTT_PUBLISH_MSG_INTENT)) {
handlePublishMessageIntent(intent);
}
if (action.equalsIgnoreCase(MQTTConstants.MQTT_UNSUBSCRIBE_TOPIC_INTENT)) {
handleUnsubscribeTopicIntent(intent);
}
}
return true;
}
I am fairly new to android, java, and mainly jsonrpc...
I have been stuck on this error for some time and i dont know if it is how i have coded it that is causing the issue or if i am trying to connect to the wrong server...
If you could help, it would be GREATLY appreciated.
here is the error code and the important code:
09-08 12:36:12.141: W/System.err(30361): Network exception: failed to connect to /10.10.11.75 (port 18332): connect failed: ECONNREFUSED (Connection refused)
09-08 12:36:12.151: W/dalvikvm(30361): threadid=11: thread exiting with uncaught exception (group=0x417df2a0)
09-08 12:36:12.151: E/AndroidRuntime(30361): FATAL EXCEPTION: AsyncTask #1
09-08 12:36:12.151: E/AndroidRuntime(30361): java.lang.RuntimeException: An error occured while executing doInBackground()
at android.os.AsyncTask$3.done(AsyncTask.java:299)
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 android.os.AsyncTask$SerialExecutor$1.run(AsyncTask.java:230)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1076)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:569)
at java.lang.Thread.run(Thread.java:856)
Caused by: java.lang.NullPointerException
at com.bitcoinapp.MainActivity.connect(MainActivity.java:219
at com.bitcoinapp.MainActivity.access$0(MainActivity.java:157)
at com.bitcoinapp.MainActivity$BitcoinConnect.doInBackground(MainActivity.java:143)
at com.bitcoinapp.MainActivity$BitcoinConnect.doInBackground(MainActivity.java:1)
at android.os.AsyncTask$2.call(AsyncTask.java:287)
at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:305)
09-08 12:36:12.151: E/AndroidRuntime(30361): ... 5 more
this is the android code that i am using at the moment... all of which is run once the user presses the button on the application. I am working off my SAMSUNG S3 MINI and not an emulator.
I have had to omit some of the content, so showing line numbers wont help, but i have added in the ones that i think are important...
class Connection implements OnClickListener {
#Override
public void onClick(View v) {
// TODO Auto-generated method stub
new BitcoinConnect().execute();
}
}
private class BitcoinConnect extends AsyncTask<String, Integer, Object[]> {
#Override
protected Object[] doInBackground(String... params) {
// TODO Auto-generated method stub
connect();
return null;
}
}
public class BasicAuthenticator implements ConnectionConfigurator {
public void configure(HttpURLConnection connection) {
// add custom HTTP header
connection.addRequestProperty("myusername", "mypassword");
}
}
private void connect() { //(line 157)
//This is the code for the JSONRPC2-CLIENT iteraction
// The JSON-RPC 2.0 server URL
URL serverURL = null;
try {
serverURL = new URL("http://10.10.11.75:18332");
} catch (MalformedURLException e) {
// handle exception...
e.printStackTrace();
}
// Create new JSON-RPC 2.0 client session
JSONRPC2Session mySession = new JSONRPC2Session(serverURL);
mySession.setConnectionConfigurator(new BasicAuthenticator());
//This is for the bitcoin BASE interaction.
//for the Bitcoin Payment Request
String method = "getinfo";
Map<String,Object> params = new HashMap<String,Object>();
String id = "Request001";
JSONRPC2Request payment = new JSONRPC2Request(method, params, id);
String jsonString = payment.toString();
JSONRPC2Response response = null;
Log.i("Failed0", "Failed0");
try {
response = mySession.send(payment);
Log.i("response", String.valueOf(response));
mTextView.setText((CharSequence) response);
} catch (JSONRPC2SessionException e) {
System.err.println(e.getMessage());
// handle exception...
Log.i("response", String.valueOf(response));
}
// Print response result / error
if (response.indicatesSuccess()) { //(line 219)
System.out.println(response.getResult());
} else {
System.out.println(response.getError().getMessage());
}
}
I am using the JSONRPC2.0 libraries for the base code and the client code. I am trying to connect to the bitcoin testnet server. The IP there is one of many that i have tried...
I know that testnet is on port 18332 and the mainnet is 8332...
ive tried a localhost IP and that hasnt worked either.
I dont know if there is suppose to be other code that i must use in order for my phone to connect to the bitcoin server...
Please help me, thanks in advance
Lets apply some logical thinking.
According to the stack trace, the NullPointerException was thrown here:
if (response.indicatesSuccess()) {
That means response was null. (No other alternative!)
That means that the send call in
response = mySession.send(payment);
EITHER returned assigned null to response, OR it through a JSONRPC2SessionException that you caught.
I suspect it was the latter, and that the message "Network exception: failed to connect to /10.10.11.75 (port 18332): ..." was logged in the process. However, the evidence is not convincing. (There aren't any "I/..." lines in the logcat output ...)
In summary, what you have done is catch the exception that told you that the send has failed, and then proceed to try to process the non-existent response!
The underlying problem is that you app cannot connect to 10.10.11.75 on port 18332. I assume that you realize that 10.10.11.75 is a private IP address, and hence that you will only be able to connect to it if the server is on your local network.