IBinder获取手机服务信息异常

 

小米8 利用IBinder transact获取服务的接口名字,结果出现以下异常:

W/System.err: java.lang.SecurityException
W/System.err:     at android.os.BinderProxy.transactNative(Native Method)
W/System.err:     at android.os.BinderProxy.transact(BinderProxy.java:482)
W/System.err:     at com.gamesec.essential.Essential.getInterfaceName(Essential.java:182)
W/System.err:     at com.gamesec.essential.Essential.getRunningServiceInfo(Essential.java:204)
W/System.err:     at com.gamesec.essential.Essential.getEssential(Essential.java:134)
W/System.err:     at com.gamesec.DataCollector.collectDeviceInfo(DataCollector.java:373)
W/System.err:     at com.gamesec.DataCollectorThread.run(DataCollectorThread.java:12)

 

手机系统为android9.0,所以查看源码 /.core/jni/android_util_Binder.cpp文件

 

android_os_BinderProxy_transact

[ android_util_Binder.cpp]

static jboolean android_os_BinderProxy_transact(JNIEnv* env, jobject obj,jint code, jobject dataObj, jobject replyObj, jint flags) // throws RemoteException
{if (dataObj == NULL) {jniThrowNullPointerException(env, NULL);return JNI_FALSE;}Parcel* data = parcelForJavaObject(env, dataObj);if (data == NULL) {return JNI_FALSE;}Parcel* reply = parcelForJavaObject(env, replyObj);if (reply == NULL && replyObj != NULL) {return JNI_FALSE;}IBinder* target = getBPNativeData(env, obj)->mObject.get();if (target == NULL) {jniThrowException(env, "java/lang/IllegalStateException", "Binder has been finalized!");return JNI_FALSE;}ALOGV("Java code calling transact on %p in Java object %p with code %" PRId32 "\n",target, obj, code);bool time_binder_calls;int64_t start_millis;if (kEnableBinderSample) {// Only log the binder call duration for things on the Java-level main thread.// But if we don'ttime_binder_calls = should_time_binder_calls();if (time_binder_calls) {start_millis = uptimeMillis();}}//printf("Transact from Java code to %p sending: ", target); data->print();status_t err = target->transact(code, *data, reply, flags);//if (reply) printf("Transact from Java code to %p received: ", target); reply->print();if (kEnableBinderSample) {if (time_binder_calls) {conditionally_log_binder_call(start_millis, target, code);}}if (err == NO_ERROR) {return JNI_TRUE;} else if (err == UNKNOWN_TRANSACTION) {return JNI_FALSE;}signalExceptionForError(env, obj, err, true /*canThrowRemoteException*/, data->dataSize());return JNI_FALSE;
}

这里会有异常抛出:

  1. 当抛出异常NullPointerException: 代表dataObj为空,意味着java层传递下来的parcel data数据为空
  2. 当抛出异常IllegalStateException: 代表BpBinder为空,意味着Native层的BpBinder已经被释放
  3. 当进入signalExceptionForError(): 根据transact执行具体情况抛出相应的异常,具体看signalExceptionForError内部实现
void signalExceptionForError(JNIEnv* env, jobject obj, status_t err, bool canThrowRemoteException, int parcelSize) {switch (err) {case UNKNOWN_ERROR:jniThrowException(env, "java/lang/RuntimeException", "Unknown error");break;case NO_MEMORY:jniThrowException(env, "java/lang/OutOfMemoryError", NULL);break;case INVALID_OPERATION:jniThrowException(env, "java/lang/UnsupportedOperationException", NULL);break;case BAD_VALUE:jniThrowException(env, "java/lang/IllegalArgumentException", NULL);break;case BAD_INDEX:jniThrowException(env, "java/lang/IndexOutOfBoundsException", NULL);break;case BAD_TYPE:jniThrowException(env, "java/lang/IllegalArgumentException", NULL);break;case NAME_NOT_FOUND:jniThrowException(env, "java/util/NoSuchElementException", NULL);break;case PERMISSION_DENIED:jniThrowException(env, "java/lang/SecurityException", NULL);break;case NOT_ENOUGH_DATA:jniThrowException(env, "android/os/ParcelFormatException", "Not enough data");break;case NO_INIT:jniThrowException(env, "java/lang/RuntimeException", "Not initialized");break;case ALREADY_EXISTS:jniThrowException(env, "java/lang/RuntimeException", "Item already exists");break;case DEAD_OBJECT:jniThrowException(env, canThrowRemoteException? "android/os/DeadObjectException": "java/lang/RuntimeException", NULL);break;case UNKNOWN_TRANSACTION:jniThrowException(env, "java/lang/RuntimeException", "Unknown transaction code");break;case FAILED_TRANSACTION: {ALOGE("!!! FAILED BINDER TRANSACTION !!! (parcel size = %d)", parcelSize);const char* exceptionToThrow;char msg[128];//transaction失败的底层原因有可能很多种,这里无法确定是那种,后续binder driver会进一步完善if (canThrowRemoteException && parcelSize > 200*1024) {exceptionToThrow = "android/os/TransactionTooLargeException";snprintf(msg, sizeof(msg)-1, "data parcel size %d bytes", parcelSize);} else {exceptionToThrow = (canThrowRemoteException)? "android/os/DeadObjectException": "java/lang/RuntimeException";snprintf(msg, sizeof(msg)-1,"Transaction failed on small parcel; remote process probably died");}jniThrowException(env, exceptionToThrow, msg);} break;case FDS_NOT_ALLOWED:jniThrowException(env, "java/lang/RuntimeException","Not allowed to write file descriptors here");break;case UNEXPECTED_NULL:jniThrowNullPointerException(env, NULL);break;case -EBADF:jniThrowException(env, "java/lang/RuntimeException","Bad file descriptor");break;case -ENFILE:jniThrowException(env, "java/lang/RuntimeException","File table overflow");break;case -EMFILE:jniThrowException(env, "java/lang/RuntimeException","Too many open files");break;case -EFBIG:jniThrowException(env, "java/lang/RuntimeException","File too large");break;case -ENOSPC:jniThrowException(env, "java/lang/RuntimeException","No space left on device");break;case -ESPIPE:jniThrowException(env, "java/lang/RuntimeException","Illegal seek");break;case -EROFS:jniThrowException(env, "java/lang/RuntimeException","Read-only file system");break;case -EMLINK:jniThrowException(env, "java/lang/RuntimeException","Too many links");break;default:ALOGE("Unknown binder error code. 0x%" PRIx32, err);String8 msg;msg.appendFormat("Unknown binder error code. 0x%" PRIx32, err);jniThrowException(env, canThrowRemoteException? "android/os/RemoteException" : "java/lang/RuntimeException", msg.string());break;}
}
struct BinderProxyNativeData {// Both fields are constant and not null once javaObjectForIBinder returns this as// part of a BinderProxy.// The native IBinder proxied by this BinderProxy.sp<IBinder> mObject;// Death recipients for mObject. Reference counted only because DeathRecipients// hold a weak reference that can be temporarily promoted.sp<DeathRecipientList> mOrgue;  // Death recipients for mObject.
};...BinderProxyNativeData* getBPNativeData(JNIEnv* env, jobject obj) {return (BinderProxyNativeData *) env->GetLongField(obj, gBinderProxyOffsets.mNativeData);
}...IBinder* target = getBPNativeData(env, obj)->mObject.get();
status_t err = target->transact(code, *data, reply, flags);

从上述代码可以看到,返回通过IBinder->transact接口返回err结果,IBinder->transact的接口可继续查看:BpBinder.transact和IPC.transact里面的实现,关于BpBinder.transact和IPC.transact的详细信息下面继续介绍:

BpBinder.transact

[ BpBinder.cpp]

status_t BpBinder::transact(uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
{if (mAlive) {//[见小节2.6]status_t status = IPCThreadState::self()->transact(mHandle, code, data, reply, flags);if (status == DEAD_OBJECT) mAlive = 0;return status;}return DEAD_OBJECT;
}

当binder死亡,则返回err=DEAD_OBJECT,所对应的抛出的异常为DeadObjectException

 

IPC.transact

[IPCThreadState.cpp]

status_t IPCThreadState::transact(int32_t handle,uint32_t code, const Parcel& data,Parcel* reply, uint32_t flags)
{status_t err = data.errorCheck(); //错误检查flags |= TF_ACCEPT_FDS;if (err == NO_ERROR) {err = writeTransactionData(BC_TRANSACTION, flags, handle, code, data, NULL);}if (err != NO_ERROR) {if (reply) reply->setError(err);return (mLastError = err); //返回writeTransactionData的执行结果err}if ((flags & TF_ONE_WAY) == 0) {if (reply) {err = waitForResponse(reply); //} else {Parcel fakeReply;err = waitForResponse(&fakeReply);}} else {err = waitForResponse(NULL, NULL);}return err; //返回waitForResponse的执行结果err
}

返回值err的来源:

  1. 返回err=DEAD_OBJECT
  2. 返回writeTransactionData的执行结果err
  3. 返回waitForResponse的执行结果err

 

IPC.waitForResponse

[IPCThreadState.cpp]

status_t IPCThreadState::waitForResponse(Parcel *reply, status_t *acquireResult)
{uint32_t cmd;int32_t err;while (1) {// 向Binder驱动写入交互if ((err=talkWithDriver()) < NO_ERROR) break;err = mIn.errorCheck();...switch (cmd) {case BR_DEAD_REPLY:err = DEAD_OBJECT;goto finish;case BR_FAILED_REPLY:err = FAILED_TRANSACTION;goto finish;default:err = executeCommand(cmd); //[见小节2.7.1]if (err != NO_ERROR) goto finish;break;}}...return err;
}

当收到BR_DEAD_REPLY,则抛出err=DEAD_OBJECT

当收到BR_FAILED_REPLY, 则抛出err=FAILED_TRANSACTION

否则返回的是executeCommand的err

 

IPC.executeCommand

status_t IPCThreadState::executeCommand(int32_t cmd){BBinder* obj;RefBase::weakref_type* refs;status_t result = NO_ERROR;switch ((uint32_t)cmd) {case BR_ERROR://从mIn中读取出错误码result = mIn.readInt32();break;...default:result = UNKNOWN_ERROR;break;}return result;}

talkWithDriver过程便会跟Binder驱动交互

当服务端收到bind请求,则此时进入execTransact()过程。

 

Binder.execTransact

[Binder.java]

private boolean execTransact(int code, long dataObj, long replyObj, int flags) {Parcel data = Parcel.obtain(dataObj);Parcel reply = Parcel.obtain(replyObj);boolean res;try {//执行onTransact方法[见小节3.1.1]res = onTransact(code, data, reply, flags);} catch (RemoteException e) {if ((flags & FLAG_ONEWAY) != 0) {Log.w(TAG, "Binder call failed.", e);} else {reply.setDataPosition(0);reply.writeException(e); //[见后续]}res = true;} catch (RuntimeException e) {if ((flags & FLAG_ONEWAY) != 0) {Log.w(TAG, "Caught a RuntimeException from the binder stub implementation.", e);} else {reply.setDataPosition(0);reply.writeException(e); //[见后续]}res = true;} catch (OutOfMemoryError e) {Log.e(TAG, "Caught an OutOfMemoryError from the binder stub implementation.", e);RuntimeException re = new RuntimeException("Out of memory", e);reply.setDataPosition(0);reply.writeException(re); //[见后续]res = true;}//[见小节3.3]checkParcel(this, code, reply, "Unreasonably large binder reply buffer");reply.recycle();data.recycle();return res;
}

可以看到服务端发送异常有3大类:

  1. RemoteException
  2. RuntimeException
  3. OutOfMemoryError

还有一类见writeException

writeException

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;} else if (e instanceof NetworkOnMainThreadException) {code = EX_NETWORK_MAIN_THREAD;} else if (e instanceof UnsupportedOperationException) {code = EX_UNSUPPORTED_OPERATION;}writeInt(code); //写入异常码StrictMode.clearGatheredViolations();if (code == 0) {if (e instanceof RuntimeException) {throw (RuntimeException) e;}throw new RuntimeException(e);}writeString(e.getMessage());
}

此处写入的异常类型:

  1. NullPointerException
  2. SecurityException
  3. BadParcelableException
  4. IllegalArgumentException
  5. IllegalStateException
  6. NetworkOnMainThreadException
  7. UnsupportedOperationException

 

checkParcel

static void checkParcel(IBinder obj, int code, Parcel parcel, String msg) {// 检查parcel数据是否大于800KBif (CHECK_PARCEL_SIZE && parcel.dataSize() >= 800*1024) {StringBuilder sb = new StringBuilder();sb.append(msg);sb.append(": on ");sb.append(obj);sb.append(" calling ");sb.append(code);sb.append(" size ");sb.append(parcel.dataSize());sb.append(" (data: ");parcel.setDataPosition(0);sb.append(parcel.readInt());sb.append(", ");sb.append(parcel.readInt());sb.append(", ");sb.append(parcel.readInt());sb.append(")");Slog.wtfStack(TAG, sb.toString());}}

 

总结异常数据传输流程如下图:

 

结论:小米手机发出安全异常是binder服务端发出的,厂商设置了权限无法访问。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/499582.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

服务动态选择域名问题

服务动态选择域名三种方案&#xff1a; 1. 通过DNS就近调度。缺点&#xff1a;DNS的ip采集库维护很麻烦。优点&#xff1a;业务无缝接入。 2. sim卡和语言判断国家&#xff0c;做国家与域名的映射&#xff0c;缺点&#xff1a;国际漫游不准确。优点&#xff1a;一般能准确路由…

安装openCV到VS2010,Win764位机时遇到的问题的解决办法

安装了一天的OpenCV&#xff0c;终于成功了&#xff0c;打算把遇到的问题和解决方案记录下来&#xff0c;以便以后再遇到时不要重蹈覆辙。 首先最常规的步骤就不说了&#xff0c;我是完全安装OpenCV中文网上的教程一步一步配置的。链接如下&#xff1a; http://wiki.opencv.o…

初学C遇到的一些知识点汇总

<span style"font-family: arial, courier new, courier, 宋体, monospace; white-space: pre-wrap;">本人是以C#为入门语言&#xff0c;现在开始学习数字图像处理&#xff0c;正在学习c语言&#xff0c;在这方面还是小白&#xff0c;所以打算把遇到的问题进行…

利用OpenCV的Haar特征目标检测方法进行人脸识别的尝试(一)

一、前言 由于还处于学习阶段&#xff0c;大多数内容都是从网上学习借鉴的&#xff0c;重复的内容就不多赘述&#xff0c;只是将自己的经验和想法分享出来。感觉不错的学习资源如下 http://www.cnblogs.com/tornadomeet/archive/2012/03/28/2420936.html http://www.cnblog…

Haar特征原理与icvCreateIntHaarFeatures方法的具体实现附详细注释—— 人脸识别的尝试系列(二)

带着强烈的兴趣&#xff0c;上周开始人脸识别的尝试与学习&#xff0c;并且将具体的操作过程记录了下来 链接如下&#xff1a;http://blog.csdn.net/u011583927/article/details/44627493 这周开始了对于算法的深入学习&#xff0c;下面进入正题。 Haar特征的原理是什么&…

createsamples.cpp中生成vec文件的实现及详细注释、图解——人脸识别的尝试系列(三)

在我们开始训练我们的Haar分类器之前&#xff0c;首先要对样本进行处理。 人脸识别的尝试系列&#xff08;一&#xff09;中&#xff1a;http://blog.csdn.net/u011583927/article/details/44627493 我们已经提到了如何准备我们的样本&#xff0c;在如下图准备好样本之后 需…

常用函数总结——sprintf

本文内容转自http://blog.csdn.net/sjf331/article/details/339254 printf 可能是许多程序员在开始学习C 语言时接触到的第二个函数&#xff08;我猜第一个是main&#xff09;&#xff0c;说 起来&#xff0c;自然是老朋友了&#xff0c;可是&#xff0c;你对这个老朋友了解多吗…

常用知识总结——信号量

本文转自http://www.cnblogs.com/tianzhiliang/archive/2010/08/31/1813635.html 信号量 Semaphore 类似互斥锁&#xff0c;但它可以允许多个线程同时访问一个共享资源 通过使用一个计数器来控制对共享资源的访问&#xff0c;如果计数器大于0&#xff0c;就允许访问&#xff0c…

设置同时上内外网+文件共享

最近做了这样一个小项目&#xff0c;逻辑是这样的。 需要在某个办公人员的电脑上装个软件&#xff0c;从局域网中的另一台电脑中读取access数据库&#xff0c;然后用apn接入某个系统的内网传输数据。 同时还要保证这个工作人员能够正常的浏览因特网。 这就涉及到了两个内容。…

浅析haartraining方法进行人脸检测

上个月用了两周的时间&#xff0c;学习了用于人脸检测的haartraining算法&#xff0c;今天打算做一总结 首先先为和我一样的初学者推荐几篇博客 http://blog.csdn.net/zouxy09/article/details/7922923真的很感谢写这篇文章的博主&#xff0c;讲解深入浅出。本文中的主要逻辑…

haartraining训练分类器方法cvCreateTreeCascadeClassifier()详解——人脸识别的尝试系列(四)

本文将介绍opencv_haartraining.exe中训练分类器的核心方法cvCreateTreeCascadeClassifier&#xff08;&#xff09;中参数的具体含义&#xff0c;以及具体实现代码附加详细的注释。最后给出运行截图以作代码阅读的参考 我们还是从具体的例子出发&#xff0c;以一些实际的参数帮…

常用知识总结——模板Template

1. 模板的概念。 我们已经学过重载(Overloading)&#xff0c;对重载函数而言,C的检查机制能通过函数参数的不同及所属类的不同。正确的调用重载函数。例如&#xff0c;为求两个数的最大值&#xff0c;我们定义MAX()函数需要对不同的数据类型分别定义不同重载(Overload)版本。 /…

opencv视频读写和视频等间隔采样

今天学习了opencv的HighGUI的内容 总结了两个视频读写demo以备以后进行视频处理和识别用 demo1 视频的读取和写入 按顺序读取视频的每一帧。对于读取的每一帧图像&#xff0c;显示在窗口中&#xff0c;然后转化为灰度图像输出到指定的文件中。 运行期间可以按ESC键退出。 还…

opencv感兴趣通道COI的使用

opencv中设置和获取感兴趣通道COI的函数如下&#xff1a; SetImageCOI 设置感兴趣通道 void cvSetImageCOI( IplImage* image, int coi ); image 图像头. coi 感兴趣通道. 函数 cvSetImageCOI 基于给定的值设置感兴趣的通道。值 0 意味着所有的通道都被选定, 1 意味着第…

Socket通用TCP通信协议设计及实现(防止粘包,可移植,可靠)

Socket通用TCP通信协议设计及实现&#xff08;防止粘包&#xff0c;可移植&#xff0c;可靠&#xff09; 引文 我们接收Socket字节流数据一般都会定义一个数据包协议。我们每次开发一个软件的通信模块时&#xff0c;尽管具体的数据内容是不尽相同的&#xff0c;但是大体上的框…

浅谈 Adaboost 算法

注&#xff1a;本文全文引用自http://blog.csdn.net/carson2005/article/details/41444289 当然作者也是转载的&#xff0c;原文是http://blog.csdn.net/haidao2009/article/details/7514787 写的很好所以转载过来以便之后再次翻阅。 一 Boosting 算法的起源 boost 算法系列的起…

如何理解离散傅里叶变换(一)实数形式傅里叶变换

如何理解离散傅里叶变换&#xff08;一&#xff09; ——实数形式傅里叶变换 ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- 本文…