一、OAID概念
OAID(Open Anonymous Identification)是一种匿名身份识别标识符,
用于在移动设备上进行广告追踪和个性化广告投放。它是由中国移动通信集
团、中国电信集团和中国联通集团共同推出的一项行业标准
OAID值为一个64位的数字
二、OAID产生的背景
在Android10以上,安卓是禁止我们获取IMEI的,那如果想要唯一标识一部手机,那我们可以使用OAID。
因传统的移动终端设备标识如国际移动设备识别码(IMEI)等已被部分国家认定为用户隐私的一部分,并存在被篡改和冒用的风险,所以在Android 10及后续版本中非厂商系统应用将无法获取IMEI、MAC等设备信息。无法获取IMEI会在用户行为统计过程中对设备识别产生一定影响。
近日移动安全联盟针对该问题联合国内手机厂商推出补充设备标准体系方案,选择OAID字段作为IMEI等的替代字段。OAID字段是由中国信通院联合华为、小米、OPPO、VIVO等厂商共同推出的设备识别字段,具有一定的权威性,可满足用户行为统计的使用场景。
三、由于OAID 引发的问题
环境:高通865 Android10 虚拟化
1、问题现象
第三方游戏应用集成了移动联盟sdk获取oaid,但是系统并没有适配oaid,导致第三方应用集成移动联盟sdk获取oaid时获取为空导致应用闪退。
2、解决思路
(1)、编写一个apk,集成到系统,开机自启,应用中定义了一个服务和重写了相对应的获取oaid的接口
(2)、定义一个oaid属性值,persist.oaid用来设置和获取oaid值
(3)、第三方应用调用移动联盟sdk获取oaid时,调用步骤1中重写的获取oaid接口,该接口通过属性值persist.oaid读取oaid的值,返回给第三方应用,这样就可以避免获取到oaid值为空情况。
3、处理步骤
3.1 编写apk,这里以适配OPPO厂商为例,每种厂商有可能重写的接口和方式不一样,这里需要注意。oppo厂商的代码如下,具体的可以下载源码查看。
BootCompletedReceiver.java代码如下:
package com.heytap.openid;
import android.app.ActivityManager;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.text.TextUtils;
import android.util.Log;
import java.util.List;
public class BootCompletedReceiver extends BroadcastReceiver {
// private final String ACTION_BOOT_COMPLETED = "com.matrixlauncher.oncreate"; //开机Launcher广播
private final String ACTION_BOOT_COMPLETED = "android.intent.action.BOOT_COMPLETED"; //系统开机广播
@Override
public void onReceive(Context context, Intent intent) {
if (intent != null) {
Log.d("CCCCC", "Oppo BootCompletedReceiveronReceive");
if (!TextUtils.isEmpty(intent.getAction()) && intent.getAction().equals(ACTION_BOOT_COMPLETED)) {
if (!isRun(context)) {
Log.d("CCCCC", "Oppo BootCompletedReceiveronReceive start IdentifyService");
context.startService(new Intent(context, IdentifyService.class));
}
}
}
}
/**
* 判断应用是否在运行
*
* @param context
* @return
*/
public boolean isRun(Context context) {
ActivityManager am = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
List<ActivityManager.RunningTaskInfo> list = am.getRunningTasks(100);
boolean isAppRunning = false;
String MY_PKG_NAME = "com.heytap.openid";
//100表示取的最大的任务数,info.topActivity表示当前正在运行的Activity,info.baseActivity表系统后台有此进程在运行
for (ActivityManager.RunningTaskInfo info : list) {
if (info.topActivity.getPackageName().equals(MY_PKG_NAME) || info.baseActivity.getPackageName().equals(MY_PKG_NAME)) {
isAppRunning = true;
break;
}
}
return isAppRunning;
}
}
IdentifyService.java代码如下:
package com.heytap.openid;
import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
import android.os.RemoteException;
import android.util.Log;
import androidx.annotation.Nullable;
public class IdentifyService extends Service {
@Override
public void onCreate() {
super.onCreate();
Log.d("CCCCC", "Oppo IdentifyService onCreate()");
}
@Nullable
@Override
public IBinder onBind(Intent intent) {
return binder;
}
private final IOpenID.Stub binder = new IOpenID.Stub() {
@Override
public String getSerID(String pkgName, String sign, String type) throws RemoteException {
Log.d("CCCCC", "Oppo OpenDeviceIdentifierService.Stub getOaid=" + SysProp.get("persist.oaid", ""));
return SysProp.get("persist.oaid", "");
}
};
}
IOpenID.aidl代码如下:
// IOpenID.aidl
package com.heytap.openid;
// Declare any non-default types here with import statements
interface IOpenID {
String getSerID(String pkgName, String sign, String type);
}
AndroidManifest.xml代码如下:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.heytap.openid"
android:sharedUserId="android.uid.system">
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/AppTheme">
<!-- 开机广播 -->
<receiver
android:name=".BootCompletedReceiver"
android:enabled="true"
android:exported="true">
<intent-filter>
<action android:name="com.matrixlauncher.oncreate" />
<action android:name="android.intent.action.BOOT_COMPLETED" />
</intent-filter>
</receiver>
<service android:name=".IdentifyService"
android:enabled="true"
android:exported="true">
<intent-filter>
<action android:name="action.com.heytap.openid.OPEN_ID_SERVICE" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</service>
</application>
</manifest>
代码结构如下,注意:包名那些都是固定的:
文章末尾会附上相关资料和适配华为、OPPO、三星、Vivo的应用服务源码
3.2 将编译好的apk集成到系统(集成apk的文件和位置仅供参考,有可能不一样,示例集成 OppoAnonymousId.apk)
3.2.1 Qualcomm865_vir/vendor/qcom/proprietary/prebuilt_HY11/target/product/qssi/prebuilt.mk中添加
PRODUCT_PACKAGES += OppoAnonymousId
3.2.2 Qualcomm865_vir/device/qcom/qssi/system.prop中新增属性
#oaid
persist.oaid=0
3.2.3 Qualcomm865_vir/frameworks/base/core/java/android/app/ActivityThread.java中修改manufacturer值
3.2.4 /home/wenyang/workplace/code/Qualcomm865_vir/vendor/qcom/proprietary/prebuilt_HY11/target/product/qssi/Android.mk中新增需要集成的apk
include $(CLEAR_VARS)
LOCAL_MODULE := OppoAnonymousId
LOCAL_MODULE_OWNER := qcom
LOCAL_MODULE_TAGS := optional
LOCAL_MODULE_CLASS := APPS
LOCAL_CERTIFICATE := platform
LOCAL_MODULE_SUFFIX := .apk
LOCAL_SRC_FILES := ../../.././target/product/qssi/system/app/OppoAnonymousId/OppoAnonymousId.apk
LOCAL_MULTILIB := 64
LOCAL_MODULE_PATH := $(PRODUCT_OUT)/system/app
include $(BUILD_PREBUILT)
3.2.5 device/qcom/qssi/apps_white_list.txt和 device/qcom/kona/apps_white_list.txt中添加OppoAnonymousId,如下图所示:
3.3 修改设备厂商为OPPO(和3.2.3步骤重复,建议采用3.2.3改机的形式修改,如果采用改机形式修改 ro.product.manufacturer属性值,此步骤可忽略)
ro.product.manufacturer=OPPO
3.4 修改设备厂商后,安装测试oaid test_get_oaid.apk,看看是否支持获取oaid
4、验证
4.1查看应用是否存在
pm list packages | grep com.heytap.openid
如果服务正常启动,通过上面的命令,可以查到如下结果:
或者通过如下命令查看进程是否存在:
ps -A | grep com.heytap.openid
4.2查看是否有调用重写的接口
第三方应用获取oaid时,是否有调用我们写的apk aidl中的接口,这里以oppo为例,查看日志会调用下面的接口:
oaid适配应用源码和相关资料下载链接: https://download.csdn.net/download/banzhuantuqiang/88331871