作者归档:softsim

星际宝盒CM520-79F刷机

https://www.right.com.cn/forum/thread-2451649-1-1.html
https://www.right.com.cn/forum/thread-3077311-1-1.html

最难的是拆掉底部的4个塑料片,它们挡住了螺丝。
用刀片或者最小最薄的一字螺丝刀,奋力“挑”开

 picocom  -b 115200  /dev/ttyUSB0
picocom v3.1

port is        : /dev/ttyUSB0
flowcontrol    : none
baudrate is    : 115200
parity is      : none
databits are   : 8
stopbits are   : 1
escape is      : C-a
local echo is  : no
noinit is      : no
noreset is     : no
hangup is      : no
nolock is      : no
send_cmd is    : sz -vv
receive_cmd is : rz -vv -E
imap is        : 
omap is        : 
emap is        : crcrlf,delbs,
logfile is     : none
initstring     : none
exit_after is  : not set
exit is        : no

Type [C-a] [C-h] to see available commands
Terminal ready
In:    serial
Out:   serial
Err:   serial
machid: 8010001
flash_type: 2
Hit any key to stop autoboot:  0 

按任意键盘进入uboot命令模式, 可以看到 (IPQ40XX): 提示符号

使用print命令查看当前uboot环境变量,查看serverip,然后将电脑ip固定为所查询到的ip
也可以用命令设置

setenv serverip 192.168.1.188

在Linux下可以用
https://github.com/DarinM223/tftp-server
https://github.com/sirMackk/py3tftp
做FTP
python3 main.py -p 69
要以root运行在默认端口69才可以

python daemon systemd servicce

现在的Linux基本用systemd 来管理系统服务(system’s services or daemons)

用户级别的服务
~/.config/systemd/user/python_demo_service.service

查看服务

systemctl --user list-unit-files | grep python_demo_service

参考:
https://github.com/torfsen/python-systemd-tutorial
https://medium.com/codex/setup-a-python-script-as-a-service-through-systemctl-systemd-f0cc55a42267

依赖:
https://github.com/systemd/python-systemd
https://peps.python.org/pep-3143/
https://pypi.org/project/python-daemon/
https://pypi.org/project/setproctitle/

结论:
用systemd ,然后在 main 进程里跑,不需要 daemonalize

Android BLE 连接错误133

在bluedroid gatt_api.h文件中有定义
#define GATT_ERROR 0x0085
https://developer.android.com/reference/android/bluetooth/BluetoothGatt.html#constants_2

情形一:
多次重复连接,断开,连接,断开,再连接,就可能出现此错误
调用 disconnect()后,并没有调用 close()去释放资源。
有些手机一次最多只能处理6个连接
如果依次连接 A B C D E F G 7个设备, 不用close()释放资源,到第7个设备
也会报 133 通用错误

情形2:
connectGatt 时 没有使用 BluetoothDevice.TRANSPORT_LE 参数

解决方法3:

connectGatt调用时, autoconnect设置为false会加快连接速度, 但这也会导致, 30秒内还连接不上,就会到133

设备电量低,信号弱
两个设备距离远,信号也弱
这些都会导致133错误

重新connect
或者 重新scan, 再connect

Null out any references to this BluetoothGatt object.
清空所有对 BluetoothGatt的引用。

解决方法4:
关掉蓝牙,再开
关掉手机,再开

保持蓝牙BLE非绑定设备的后台连接

对于非绑定设备(也就是扫描后连接的这种模式),Android 上 BLE 的默认行为是应用拥有与 BLE 设备的连接。相比之下,Android 操作系统拥有绑定设备的连接。

这意味着对于非绑定设备的情形,如果您的应用程序由于资源限制在后台被操作系统终止,或者如果您的用户将您的应用程序滑开(立即终止它,效果明显😃),BLE 连接将丢失,您应该会看到大多数 BLE 外围设备再次开始广告。

尝试使您的应用程序进程尽可能长时间保持活动状态的最直接方法是使用前台服务。如何实现自己的前台服务,在 官方文档里 有明确的步骤。
foreground-services

前台服务本质上是一个带着 通知抽屉中的持久横幅 运行的服务(也就是状态栏有个通知 ),让用户了解您的应用程序正在后台执行某些操作。(A foreground service is essentially a Service that runs with a persistent banner in the notification drawer, keeping the user in the loop that your app is doing something in the background. )
由于内存限制而被系统终止的概率非常低,但并非不可能。

值得注意的是,当用户在前台服务运行时滑离(swipes away )您的应用程序时,您的应用程序进程仍然存在,但您的 Activity 堆栈和任何其他面向用户的元素都会被吹走(get blown away)。因此,必须格外小心以确保您的 BLE 逻辑存在于这些实体之外,就像在一个名为 ConnectionManager 的单例中处理应用程序的所有 BLE 需求一样。

通常,您的Activities和Fragments 不应该对 BLE 连接的状态做出任何假设。相反,他们应该依赖 ConnectionManager(或任何管理应用程序 BLE 需求的实体)作为唯一的事实来源,并根据 UI 的需要在 onCreate() 和 onResume() 中相应地更新 UI。

使用前台服务也不是完全安全的,因为 Android P 及更高版本具有自适应电池功能,有时会限制运行前台服务的应用程序进程的正常运行时间,但根据我们的经验,这似乎是随机发生的。到目前为止,解决此限制的唯一方法是要求您的用户关闭应用程序的电池优化,这是隐藏在“设置”应用程序中的一个选项。

其他 Android 后台处理技术,如依赖 AlarmManager 和 WorkManager 也是可行的,但连接事件不会是即时的,并且可能会丢失一些 BLE 通知或指示,如果这些事件发生时应用程序碰巧没有运行。
也就是说,如果您的应用程序不需要在事件发生时了解它们,并且可以定期唤醒,再次连接到 BLE 设备(如果它在附近),并查询新的数据, 那么 这些后台技术就是好的,可以接受的。

BluetoothManager getConnectionState(android.bluetooth.BluetoothDevice, int)

public int getConnectionState (BluetoothDevice device, int profile)

得到 远程设备profile的 连接状态
profile 为 GATT 或者 GATT_SERVER

返回值为:
STATE_DISCONNECTED = 0
STATE_CONNECTING = 1
STATE_CONNECTED = 2
STATE_DISCONNECTING = 3

BluetoothAdapter.getProfileConnectionState(int profile)
profile只能为 BluetoothProfile#HEADSET 或者 BluetoothProfile#A2DP.

    @SuppressLint("MissingPermission")
    public boolean isConnected() {
        if(mBluetoothGatt != null) {
             int state = mBluetoothManager.getConnectionState(mBluetoothGatt.getDevice(),  BluetoothProfile.GATT);
             return state == BluetoothProfile.STATE_CONNECTED;
        }
        return false;
    }

Android Activity requestPermissions

https://android.googlesource.com/platform/frameworks/base/+/master/core/java/android/app/Activity.java

        if (mHasCurrentPermissionsRequest) {
            Log.w(TAG, "Can request only one set of permissions at a time");
            // Dispatch the callback with empty arrays which means a cancellation.
            onRequestPermissionsResult(requestCode, new String[0], new int[0]);
            return;
        }

崩溃的地方, 一次只能请求一个权限集合

android native线程调用jni找不到Java Class

线程

所有线程(包括Java线程)都是 Linux 线程,由内核调度。

线程通常从受管理代码(Java代码)启动(使用 Thread.start()),但也可以在其他位置创建,然后附加到 JavaVM。

例如,可以使用 AttachCurrentThread() 或 AttachCurrentThreadAsDaemon() 函数附加通过 pthread_create() 或 std::thread 启动的线程。在附加之前,线程不包含任何 JNIEnv,也无法调用 JNI。

通常,最好使用 Thread.start() 创建需要调用 Java 代码的任何线程

这样做可以确保您有足够的堆栈空间、属于正确的 ThreadGroup 且与您的 Java 代码使用相同的 ClassLoader

而且,设置线程名称以在 Java 中进行调试也比通过原生代码更容易(如果您有 pthread_t 或 thread_t,请参阅 pthread_setname_np();如果您有 std::thread 且需要 pthread_t,请参阅 std::thread::native_handle())。

附加原生创建的线程会构建 java.lang.Thread 对象并将其添加到“主”ThreadGroup,从而使调试程序能够看到它。在已附加的线程上调用 AttachCurrentThread() 属于空操作。

Android 不会挂起执行原生代码的线程。如果正在进行垃圾回收,或者调试程序已发出挂起请求,则在线程下次调用 JNI 时,Android 会将其挂起。

通过 JNI 附加的线程在退出之前必须调用 DetachCurrentThread()。如果直接对此进行编码会很棘手,在 Android 2.0 (Eclair) 及更高版本中,您可以先使用 pthread_key_create() 定义将在线程退出之前调用的析构函数,之后再调用 DetachCurrentThread()。(将该键与 pthread_setspecific() 搭配使用,将 JNIEnv 存储在线程本地存储中;这样一来,该键将作为参数传递到您的析构函数中。)

===========
运行时可以通过两种方式找到您的原生方法。您可以使用 RegisterNatives 显示注册原生方法,也可以让运行时使用 dlsym 进行动态查找。RegisterNatives 的优势在于,您可以预先检查符号是否存在,而且还可以通过只导出 JNI_OnLoad 来获得规模更小、速度更快的共享库。
让运行时发现函数的优势在于,要编写的代码稍微少一些。

如需使用 RegisterNatives,请执行以下操作:
1) 提供 JNIEXPORT jint JNI_OnLoad(JavaVM* vm, void* reserved) 函数。
2) 在 JNI_OnLoad 中,使用 RegisterNatives 注册所有原生方法。
3) 使用 -fvisibility=hidden 进行构建,以便只从您的库中导出您的 JNI_OnLoad。这将生成速度更快且规模更小的代码,并避免与加载到应用中的其他库发生潜在冲突(但如果应用在原生代码中崩溃,则创建的堆栈轨迹用处不大)。

从 JNI_OnLoad 进行的任何 FindClass 调用都会在用于加载共享库的类加载器的上下文中解析类。
从其他上下文调用时,FindClass 会使用与 Java 堆栈顶部的方法相关联的类加载器,如果没有(因为调用来自刚刚附加的原生线程),则会使用“系统”类加载器。

由于系统类加载器不知道应用的类,因此您将无法在该上下文中使用 FindClass 查找您自己的类

这使得 JNI_OnLoad 成为查找和缓存类的便捷位置:一旦有了有效的 jclass,您就可以从任何附加的线程使用它。

==============
常见问题解答:为什么 FindClass 找不到我的类?

如果类名称形式正确,则可能是您遇到了类加载器问题。FindClass 需要在与您的代码关联的类加载器中启动类搜索。它会检查调用堆栈,如下所示:

    Foo.myfunc(Native Method)
        Foo.main(Foo.java:10)

最顶层的方法是 Foo.myfunc。
FindClass 会查找与 Foo 类关联的 ClassLoader 对象并使用它。

采用这种方法通常会完成您想要执行的操作。如果您自行创建线程(可能通过调用 pthread_create,然后使用 AttachCurrentThread 进行附加),可能会遇到麻烦。现在您的应用中没有堆栈帧。如果从此线程调用 FindClass,JavaVM 会在“系统”类加载器(而不是与应用关联的类加载器)中启动,因此尝试查找特定于应用的类将失败。

您可以通过以下几种方法来解决此问题:

1. 在 JNI_OnLoad 中执行一次 FindClass 查找,然后缓存类引用以供日后使用。在执行 JNI_OnLoad 过程中发出的任何 FindClass 调用都会使用与调用 System.loadLibrary 的函数关联的类加载器(这是一条特殊规则,用于更方便地进行库初始化)。如果您的应用代码要加载库,FindClass 会使用正确的类加载器。

2. 通过声明原生方法来获取 Class 参数,然后传入 Foo.class,从而将类的实例传递给需要它的函数。

3. 在某个便捷位置缓存对 ClassLoader 对象的引用,然后直接发出 loadClass 调用。这需要花费一些精力来完成。

android udp操作权限

https://developer.android.com/training/basics/network-ops/connecting
若要在您的应用中执行网络操作,您的清单必须包含以下权限

uses-permission android:name="android.permission.INTERNET"
uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"

Operation not permitted (os error 1)
Permission denied (os error 13)

如果不声明,udp bind就会报错

Android 11 上的软件包可见性过滤

如果应用以 Android 11(API 级别 30)或更高版本为目标平台,并查询与设备上已安装的其他应用相关的信息,则系统在默认情况下会过滤此信息。从您的应用的角度来看,有限的软件包可见性会减少设备上显示的已安装应用数。

此过滤行为有助于最大限度减少显示您的应用在实现其用例时不需要的潜在敏感信息,但您的应用仍然可以访问这些信息。此外,过滤后的软件包可见性可帮助 Google Play 等应用商店评估应用为用户提供的隐私权和安全性。例如,Google Play 会将已安装应用的列表视为个人和敏感用户数据。

有限的应用可见性会影响提供其他应用相关信息的方法的返回结果,例如 queryIntentActivities()、getPackageInfo() 和 getInstalledApplications()。

有限的可见性还会影响与其他应用的显式交互,例如启动另一个应用的服务

某些软件包仍然自动可见。您的应用始终可以在查询其他已安装的应用时看到这些软件包。
=====================================
系统会自动让部分应用对您的应用可见,以便您的应用可与其交互,而无需声明 queries 元素。此行为有助于支持基本功能和常见用例。

即使您的应用以 Android 11(API 级别 30)或更高版本为目标平台,以下类型的应用也始终对您的应用可见:

您自己的应用。
实现 Android 核心功能的某些系统软件包,例如媒体提供程序。
安装了您应用的应用。
使用 startActivityForResult() 方法在您的应用中启动 activity 的任何应用,正如如何获取 activity 的结果这一指南中所述。
启动或绑定到您应用中的某项服务的任何应用。
访问您应用中的 Content Provider 的任何应用。
具有 Content Provider 的任何应用,其中您的应用已被授予 URI 权限来访问该 Content Provider。
接收您应用的输入的任何应用。这种情况仅适用于您的应用作为输入法应用提供输入。

此外,您可以使用隐式或显式 intent 来启动另一应用的 activity,无论这个应用是否对您的应用可见。

实现 Android 核心功能的某些系统软件包会自动对您的应用可见,即使您的应用以 Android 11 或更高版本为目标平台也是如此。这组特定的软件包取决于运行您应用的设备。

如需查看特定设备的完整软件包列表,请在开发机器上的终端中运行以下命令:

adb shell dumpsys package queries

在命令输出中,找到 forceQueryable 部分

=====================================

如需查看其他软件包,请使用 query 元素声明您的应用需要提高软件包可见性。

在极少数情况下,如果遇到 元素无法提供适当的软件包可见性,您还可以使用 QUERY_ALL_PACKAGES 权限。如果您在 Google Play 上发布应用,那么应用是否此权限需要根据即将生效的政策进行批准。

QMI UIM APDU Security Restrictions

qmi_uim.c ADPU rejected due to security restrictions: logical_channel doesnt belong to client

将 NV 67312 (QMI UIM APDU Security Restrictions)设置为0, 可以移除APDU 限制.

此NV项目不能用QXDM工具修改,必须写入 HW MBN 才能生效

所以需要编译modem源代码
modem_proc/mcfg/mcfg_gen/generic/common/Default/mcfg_hw_gen_Default.xml

 <NvEfsItemData name="apdu_security_restrictions" id="67312" description="APDU Security Restrictions" comment="" category="UIM" mcfgAttributes="0x09" mcfgVariant="2" fullpathname="/nv/item_files/modem/qmi/uim/apdu_security_restrictions"> <Member name="apdu_security_restrictions" description="" comment="" sizeOf="1" type="uint8">0 </Member>
 </NvEfsItemData>

重新编译生成 Non-Hlos.bin

用QPST EFS Explorer 也无法 往 /nv/item_files/modem/qmi/uim 目录写入 apdu_security_restrictions 文件,写入别的名称文件倒是可以