Exceptions that look like this are confusing:
FATAL EXCEPTION: main
java.lang.NullPointerException
at android.os.Parcel.readException(Parcel.java:1437)
at android.os.Parcel.readException(Parcel.java:1385)
at com.yourpackage.ipc.IYourClass$Stub$Proxy.yourMethod(IYourClass.java:488)
at com.yourpackage.ipc.YourClassShim.yourMethod(YourClassShim.java:269)
I found a bunch of related questions for this, but none with the answer to "how do you debug this". So I'm making this Question/Answer.
By looking at the android source here and here you'll see that it can be throwing any of these (the NullPointerException is just what I had):
SecurityException(msg);
BadParcelableException(msg);
IllegalArgumentException(msg);
NullPointerException(msg);
IllegalStateException(msg);
RuntimeException("Unknown exception code: " + code + " msg " + msg);
But what's causing these?
What's going on here is that readException() is checking the IPC byte stream for a header that says that an exception occurred; if it finds one, then it throws a new exception of that type, with the same message, but missing the original stack trace. (It only actually knows a few exception types; anything else gets translated into a base RuntimeException.)
So where's the original exception coming from? Well, somewhere down in the guts of the real implementation of YourClass.yourMethod() -- not in any of the parcelable or IPC code. So go there, wrap the whole method in a try/catch, and log whatever you caught.
(Or set a breakpoint there if you've got remote process breakpoints working.)
I think android SHOULD provide more binder remote exception information
so i modify Parcel.java to wrap more binder remote exception information
public final void writeException(Exception e) {
int code = 0;
if (e instanceof SecurityException) {
code = EX_SECURITY;
} else if (e instanceof BadParcelableException) {
code = EX_BAD_PARCELABLE;
} else if (e instanceof IllegalArgumentException) {
code = EX_ILLEGAL_ARGUMENT;
} else if (e instanceof NullPointerException) {
code = EX_NULL_POINTER;
} else if (e instanceof IllegalStateException) {
code = EX_ILLEGAL_STATE;
}
writeInt(code);
StrictMode.clearGatheredViolations();
if (code == 0) {
if (e instanceof RuntimeException) {
throw (RuntimeException) e;
}
throw new RuntimeException(e);
}
// I replace writeString(e.getMessage()) with writeString(remoteExceptionToString(e))
writeString(remoteExceptionToString(e));
}
static String remoteExceptionToString(Exception e) {
final StringWriter sw = new StringWriter(1024);
final PrintWriter pw = new PrintWriter(sw, true);
pw.println();
e.printStackTrace(pw);
return sw.toString().replace("\n", String.format("\n(%5d %5d): ", Process.myPid(), Process.myTid()));
}
SerializeExceptionSecondService defination:
public class SerializeExceptionSecondService extends Service {
private static final String TAG = "SerializeExceptionSecondService";
public SerializeExceptionSecondService() {
}
#Override
public IBinder onBind(Intent intent) {
// TODO: Return the communication channel to the service.
return mServiceBinder;
}
private final ISerializeExceptionSecondService.Stub mServiceBinder = new ISerializeExceptionSecondService.Stub() {
#Override
public void throwException() throws RemoteException {
// TODO Auto-generated method stub
Log.e(TAG, "throwException");
throw new IllegalStateException("Cause1", new IllegalStateException("Cause2", new IllegalStateException("Cause3")));
}
#Override
public void noThrowException() throws RemoteException {
// TODO Auto-generated method stub
}
};
}
AndroidManifest.xml fragment:
<service
android:name=".SerializeExceptionSecondService"
android:enabled="true"
android:exported="true"
android:process=":second_remote" >
</service>
in this way, the binder exception logcat will look like the below:
Related
I have a button in my MapsActivity that communicates to the Wear app. The following Thread is executed:
class NewThread extends Thread {
String path;
String message;
NewThread(String p, String m) {
path = p;
message = m;
}
public void run() {
Task<List<Node>> wearableList =
Wearable.getNodeClient(getApplicationContext()).getConnectedNodes();
try {
List<Node> nodes = Tasks.await(wearableList);
for (Node node : nodes) {
Task<Integer> sendMessageTask =
Wearable.getMessageClient(MapsActivity.this).sendMessage(node.getId(), path, message.getBytes());
try {
Integer result = Tasks.await(sendMessageTask);
sendmessage("I just sent the wearable a message " + sentMessageNumber++);
} catch (final ExecutionException exception) {
MapsActivity.this.runOnUiThread(new Runnable() {
#Override
public void run() {
Toasty.error(MapsActivity.this, "[1] Something went wrong. Error details: " + exception.getMessage()).show();
}
});
} catch (final InterruptedException exception) {
MapsActivity.this.runOnUiThread(new Runnable() {
#Override
public void run() {
Toasty.error(MapsActivity.this, "[2] Something went wrong. Error details: " + exception.getMessage()).show();
}
});
}
}
} catch (final ExecutionException exception) {
MapsActivity.this.runOnUiThread(new Runnable() {
#Override
public void run() {
Toasty.error(MapsActivity.this, "[3] Something went wrong. Error details: " + exception.getMessage()).show();
}
});
} catch (final InterruptedException exception) {
MapsActivity.this.runOnUiThread(new Runnable() {
#Override
public void run() {
Toasty.error(MapsActivity.this, "[4] Something went wrong. Error details: " + exception.getMessage()).show();
}
});
}
}
}
But I get the following error in the image when trying to accomplish the Thread.
This happens on an Emulator where the WearOS app/api is not available to me (Probably on real devices which do not have WearOS App/Api too).
It happens on the Wearable.getMessageClient(MapsActivity.this).sendMessage(node.getId(), path, message.getBytes());.
I didn't find a clean way of checking the Wear API to be available so I am trying to get the capabilities first, catching the ApiException and setting a isWearableAvailable property:
private fun checkCapability() {
try {
val capability = capabilityClient
.getCapability(CAPABILITY_XYZ, CapabilityClient.FILTER_REACHABLE)
.await()
isConnected = capability.nodes.any(Node::isNearby)
if (BuildConfig.DEBUG) Log.d(LOG_TAG,
"Capability: ${capability.nodes.joinToString()}} > ${isConnected}")
isWearableApiAvailable = true
} catch (e: ApiException) {
isWearableApiAvailable = false
}
}
Situation : A function calls a thread to send data to the server. This thread in turn spawns yet another thread, to obtain results from the server using ObjectInputStream().
Finally, this object is returned to the calling function by the spawned thread.
Note: The threads are Callable and are synchronized.
Problem : I get an exception, "FutureTask cannot be cast to MyClassName".
I didn't find a solution to this on the web. Any suggestions ?
Client Code:
public synchronized Object invoke(Object proxy, Method m, Object[] args) throws Throwable
{
try {
// Lots of if-else statements
//.........
else if (m.toString().contains("getPosition"))
{
if (!offload){
Log.d("DProxy","Sprite Redirection takes place here 6 "+m.invoke(v, args).toString());
//System.out.println("PROXY Tick Argument is ");
return m.invoke(v, args);
}
else
{
//Code to create THREAD on the Endpoint
if (endpoint !=null)
{
if (!serialized)
{
System.out.println("serializing via proxy itself 11");
this.endpoint.serialize(obj);
serialized = true;
}
Object[] args1 = new Object[args.length+1];
for (i=0;i<args.length;i++)
args1[i]=args[i];
args1[i]= m.toString();
// ** Error is thrown at this line below**
Vec2 tmp = (Vec2) this.endpoint.onClick(args1);
return tmp;
//return null;
}
else
System.out.println("Endpoint is NULL");
}
}
onclick() method.
public synchronized Object onClick(Object[] args) {
try {
latch.await();
ctr++;
Log.d("CLIENT","Sending Param to Client "+args[args.length-1].toString()+" "+ctr);
objectOutputStream.writeBoolean(false);
// TEMP Commented
objectOutputStream.flush();
objectOutputStream.reset();
objectOutputStream.writeObject(args);
Callable<Object> worker = (Callable<Object>) new ClientThread(thisSocket,ctr);
return executor.submit(worker);
}catch (Exception e)
{
Log.e("ENDPOINT Exception",e.toString());
}
Log.e("ENDPOINT","Returning blank Object");
return new Object();
}
class ClientThread implements Callable <Object>{//Runnable {
private int ctr;
public ClientThread(Socket socket, int ctr)
{
this.ctr = ctr;
}
public synchronized Object call() {
Vec2 res1 = null;
Double res2=null;
Object res = null;
try {
Log.v("CLIENT","Attempting to receive results from Server "+ctr);
res = objectInputStream.readObject();
if (res instanceof Vec2)
{
res1 = (Vec2) res;
Log.v("CLIENT", "Object received Vec2 "+ctr);
}
else if (res instanceof Double)
{
res2 = (Double) res;
Log.v("CLIENT", "Object received Double "+ctr);
}
else
if(res==null)
Log.v("CLIENT", "Object received is NULL "+ctr);
else
Log.v("CLIENT", "Object received of UNKNOWN Type "+ctr);
} catch (UnknownHostException e1) {
Log.e("CLIENT receive error 1",e1.toString());
} catch (IOException e1) {
Log.e("CLIENT receive error 2",e1.toString());
}
catch (Exception e)
{
Log.e("CLIENT receive error 3",e.toString());
}
if (res1 !=null)
return res1;
else
if (res2!=null)
return res2;
else
return res;
}
//}
}
Any object can not be casted to any class or interface except classes/interfaces it extends/implements. FutureTask implements interfaces RunnableFuture, Runnable and Future.
OK its gone now. I just implemented ClientThread's code as merely a function call !
Strange are the ways of Java.....
I am a beginner in android programming.
I want to use the hidden method "getState()" of "com.android.internal.telephony.call" package to manage the state of an outgoing call such as activating, ringing, answering, rejecting and disconnecting.
But there is an error in the following code on the line indicated by "**".
Any help?
My code is :
import com.android.internal.telephony.*;
public class MainActivity extends Activity {
Class myclass;
ClassLoader cloader;
Method f;
Object o;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
cloader = this.getClass().getClassLoader();
try {
myclass = cloader.loadClass("com.android.internal.telephony.Call");
// No error generated. "Call" class will be loaded.
}
catch (Exception e)
{
System.out.println(e.toString());
}
try {
f = myclass.getMethod("getState", null);
// No error generated.Method "f" will be assigned
} catch (Exception e) {
System.out.println(e.toString());
}
Constructor constructors[] = myclass.getDeclaredConstructors();
// There is one constructor only
Constructor constructor = null;
for (int i=0; i<constructors.length;i++)
{
constructor = constructors[i];
if (constructor.getGenericParameterTypes().length == 0)
break;
}
constructor.setAccessible(true);
try {
o = constructor.newInstance(null);
//*****an exception generated here.
//*****Exception is "java.lang.instantationexception"
}
catch (Exception e) {
System.out.println(e.toString());
}
try {
f = myclass.getMethod("getState", null);
// No error
} catch (Exception e) {
System.out.println(e.toString());
}
}
Don't try to call private members like this. It will not work across Android versions and even across manufacturer customized ROMs of the same version.
I am using netty-3.6.6 SSL in my Android app. The handshake() is actually done(Android app is able to send/receive data to/from SSL server) but operationComplete never gets called. I need it getting called to perform some tasks.
Anything I missed or did wrong? Thank you.
Follows are the settings and the code piece.
#Override
public ChannelPipeline getPipeline() throws Exception {
ChannelPipeline pip = Channels.pipeline();
SSLEngine engine = SslContextFactory.getClientContext().createSSLEngine();
engine.setUseClientMode(true);
SslHandler sslHandler = new SslHandler(engine);
sslHandler.setIssueHandshake(false);
pip.addLast("ssl", sslHandler);
...
return pip;
}
#Override
public void channelConnected(ChannelHandlerContext ctx, ChannelStateEvent e) throws Exception {
System.out.println("channelConnected");
SslHandler sslHandler = ctx.getPipeline().get(SslHandler.class);
if (sslHandler != null) {
// Begin handshake.
ChannelFuture handshakeFuture = sslHandler.handshake();
handshakeFuture.addListener(new ChannelFutureListener() {
#Override
public void operationComplete(ChannelFuture future) throws Exception {
if (!future.isSuccess()) {
System.out.println("handshake failed(" + future.getCause() + ")");
} else {
System.out.println("handshake OK");
}
}
});
}
}
}
netty might not handle the state of ChannelFuture returned to my application which calls SslHandler.handshake() correctly. I added hsFuture.setSuccess() to SslHandler.handshake() and my operationComplete gets called.
public ChannelFuture handshake() {
...
if (exception == null) { // Began handshake successfully.
try {
final ChannelFuture hsFuture = handshakeFuture;
wrapNonAppData(ctx, channel).addListener(new ChannelFutureListener() {
public void operationComplete(ChannelFuture future) throws Exception {
if (!future.isSuccess()) {
Throwable cause = future.getCause();
hsFuture.setFailure(cause);
fireExceptionCaught(ctx, cause);
if (closeOnSSLException) {
Channels.close(ctx, future(channel));
}
} else {
hsFuture.setSuccess();
}
}
});
} catch (SSLException e) {
This question already has answers here:
AsyncTask and error handling on Android
(12 answers)
Closed 9 years ago.
Currently I'm working on implementing network communication layer. And I thought it's good to consult with more experienced Android developers first.
I have a class called WebApiController which is responsible for: making requests and parsing responses, and storing them in the models. WebApiController methods execute on the main thread, so I wrap them in AsyncTasks to take the load out of the main thread. WebApiController methods potentially throws exceptions such as ServerBadResponseException, XmlParserException, etc. And I want to be able to handle them accordingly to the type of error (i.e. show different error messages based on the type of error). So, what would be the best way to notify the onPostExecute about the error type, and nicely handle it there.
Or this:
class SomeTask extends AsyncTask<Void, Void, Params> {
#Override
protected Params doInBackground(Void... voids) {
Params params = new Params();
try {
.....
params._result = .....
} catch (Throwable e) {
params._error = e;
}
return params;
}
#Override
protected void onPostExecute(Params params) {
if(params._error != null){
....
} else {
....
}
}
}
class Params {
public Throwable _error;
public Object _result;
}
Basically the easiest way is to set a return code like "SUCCESS", "FAILURE_XY" and process that in your onPostExecute(). This works also, when you normally would return data...
doInBackground() {
try {
// code
return data;
} catch (Exception e) {
Log.e(TAG, "error description", e);
resultCode = FAILURE;
return null;
}
}
onPostExecute(Data data) {
if (data == null) {
// check resultCode!
} else {
// work with your data
}
}
You can try this (in doInBackgroung method):
try {
........
} catch (final Throwable e) {
runOnUiThread(new Runnable() {
public void run() {
Log.e(TAG, e.getMessage(), e);
Toast.makeText(......).show();
}
});
}