导包:
implementation("com.google.android.gms:play-services-ads-identifier:18.1.0")
获取广告id的代码
new Thread(() -> {
try {
Class.forName("com.google.android.gms.ads.identifier.AdvertisingIdClient");
AdvertisingIdClient.Info advertisingIdClient$Info0 = AdvertisingIdClient.getAdvertisingIdInfo(this);
if(advertisingIdClient$Info0 == null) {
Log.e(Tag,"advertisingIdClient$Info0 == null");
}
else {
String id = advertisingIdClient$Info0.getId();
advertisingIdClient$Info0.isLimitAdTrackingEnabled();
Log.e(Tag,"advertisingId = " + id);
}
}
catch(Throwable throwable0) {
Log.e(Tag,"Google Play Services is missing " + throwable0.getMessage());
}
}).start();
这个包也只是提供了一个获取的接口,实际生成不在这个包里面
public static Info getAdvertisingIdInfo(Context context) throws IOException, IllegalStateException, GooglePlayServicesNotAvailableException, GooglePlayServicesRepairableException {
Info advertisingIdClient$Info0;
AdvertisingIdClient advertisingIdClient0 = new AdvertisingIdClient(context, -1L, true, false);
try {
long v = SystemClock.elapsedRealtime();
advertisingIdClient0.zzb(false);
advertisingIdClient$Info0 = advertisingIdClient0.zzd(-1);
advertisingIdClient0.zzc(advertisingIdClient$Info0, true, 0.0f, SystemClock.elapsedRealtime() - v, "", null);
}
catch(Throwable throwable0) {
try {
advertisingIdClient0.zzc(null, true, 0.0f, -1L, "", throwable0);
throw throwable0;
}
catch(Throwable throwable1) {
advertisingIdClient0.zza();
throw throwable1;
}
}
advertisingIdClient0.zza();
return advertisingIdClient$Info0;
}
private final Info zzd(int v) throws IOException {
Info advertisingIdClient$Info0;
……
try {
try {
advertisingIdClient$Info0 = new Info(this.zzb.zzc(), this.zzb.zze(true)); //第一个参数是广告id ,第二个参数是isLimitAdTrackingEnabled
}
catch(RemoteException remoteException0) {
Log.i("AdvertisingIdClient", "GMS remote exception ", remoteException0);
throw new IOException("Remote exception");
}
__monitor_exit(this);
}
catch(Throwable throwable0) {
__monitor_exit(this);
throw throwable0;
}
this.zze();
return advertisingIdClient$Info0;
}
Info类,第一个参数是广告id ,第二个参数是isLimitAdTrackingEnabled
public static final class Info {
private final String zza;
private final boolean zzb;
@Deprecated
public Info(String s, boolean z) {
this.zza = s;
this.zzb = z;
}
public String getId() {
return this.zza;
}
public boolean isLimitAdTrackingEnabled() {
return this.zzb;
}
@Override
public String toString() {
return "{" + this.zza + "}" + this.zzb;
}
}
zzd.zzc 返回值就是广告id,是通过binder接口跨进程获取的,后续代码就不在这个sdk里面了,相当于这个sdk就提供了获取的接口,实际值是怎么来的不在这里面。
@Override // com.google.android.gms.internal.ads_identifier.zzf
public final String zzc() throws RemoteException {
Parcel parcel0 = this.zzb(1, this.zza());
String s = parcel0.readString();
parcel0.recycle();
return s;
}
package com.google.android.gms.internal.ads_identifier;
import android.os.IBinder;
import android.os.IInterface;
import android.os.Parcel;
import android.os.RemoteException;
public class zza implements IInterface {
private final IBinder zza;
private final String zzb;
protected zza(IBinder iBinder0, String s) {
this.zza = iBinder0;
this.zzb = "com.google.android.gms.ads.identifier.internal.IAdvertisingIdService";
}
@Override // android.os.IInterface
public final IBinder asBinder() {
return this.zza;
}
protected final Parcel zza() {
Parcel parcel0 = Parcel.obtain();
parcel0.writeInterfaceToken(this.zzb);
return parcel0;
}
protected final Parcel zzb(int v, Parcel parcel0) throws RemoteException {
Parcel parcel1 = Parcel.obtain();
try {
this.zza.transact(v, parcel0, parcel1, 0);
parcel1.readException();
}
catch(RuntimeException runtimeException0) {
try {
parcel1.recycle();
throw runtimeException0;
}
catch(Throwable throwable0) {
parcel0.recycle();
throw throwable0;
}
}
catch(Throwable throwable0) {
parcel0.recycle();
throw throwable0;
}
parcel0.recycle();
return parcel1;
}
}
adb shell pm path com.google.android.gms 搜索安装包路径,然后包apk pull出来分析。
搜索上面的接口 “com.google.android.gms.ads.identifier.internal.IAdvertisingIdListener”
追踪流程
public abstract class bpub implements ServiceConnection {
public final void onServiceConnected(ComponentName componentName0, IBinder iBinder0) {
eows eows0 = this.a.j(componentName0, "onServiceConnected");
try {
this.a(componentName0, iBinder0);
}
catch(Throwable throwable0) {
if(eows0 != null) {
try {
eows0.close();
}
catch(Throwable throwable1) {
throwable0.addSuppressed(throwable1);
}
}
throw throwable0;
}
if(eows0 != null) {
eows0.close();
}
}
public final class rhp extends bpub {
@Override // bpub
public final void a(ComponentName componentName0, IBinder iBinder0) {
npz npz0;
if(iBinder0 == null) {
npz0 = null;
}
else {
IInterface iInterface0 = iBinder0.queryLocalInterface("com.google.android.gms.ads.identifier.internal.IAdvertisingIdListener");
npz0 = (iInterface0 instanceof a) ? ((a)iInterface0) : new a(iBinder0);
}
try {
int v = amza.b(this.c).d(this.a, 0).uid;
Bundle bundle0 = new Bundle();
bundle0.putString("ad_id", this.e.f(v));
bundle0.putBoolean("lat_enabled", this.e.o(v));
Parcel parcel0 = npz0.fs();
nqb.d(parcel0, bundle0);
npz0.ft(1, parcel0);
}
catch(Throwable throwable0) {
((ertf)AdvertisingIdNotificationChimeraService.a.j()).B("Failed to notify listener service of %s.", this.a);
Log.w("AdvertisingIdNS", throwable0);
}
try {
ampa.a().b(this.c, this);
}
catch(IllegalArgumentException unused_ex) {
}
this.d.release();
}
接上面bundle0.putString("ad_id", this.e.f(v));
public final String f(int v) {
boolean z;
if(((long)Build.VERSION.SDK_INT) >= furq.c() && (this.o(v))) {
if(furq.g()) {
this.j(); // this.b().edit().remove("adid_key").remove("fake_adid_key").apply();
}
if(furq.a.e().J()) {
return b.a; //b.a = new UUID(0L, 0L).toString();
}
}
String[] arr_s = amza.b(this.f).k(Binder.getCallingUid());
if(arr_s != null && arr_s.length == 1) {
String s = arr_s[0];
if(!com.google.android.gms.ads.identifier.util.d.a(s) && !com.google.android.gms.ads.identifier.util.d.b(s)) {
if(!com.google.android.gms.ads.identifier.util.d.c(s) || !fush.f()) {
goto label_13;
}
z = this.q(s, "android.permission.ACCESS_PRIVILEGED_AD_ID_COMPAT");
}
else {
z = this.q(s, "android.permission.ACCESS_PRIVILEGED_AD_ID");
}
if(z) {
goto label_27;
}
}
label_13:
if(v != -100) {
String[] arr_s1 = amza.b(this.f).k(v);
if(arr_s1 == null) {
Log.w("AdvertisingIdSettings", "Invalid caller uid. Permission check failed");
goto label_23;
}
for(int v1 = 0; v1 < arr_s1.length; ++v1) {
if(34L >= furq.b() && boik.c(this.f, "com.google.android.gms.permission.AD_ID", -1, v, arr_s1[v1], null) == -1) {
if(furq.a.e().u()) {
Log.w("AdvertisingIdSettings", "Package " + arr_s1[v1] + " failed Ad Id permission check. Apps that target Android SDK " + furq.b() + " or higher should declare com.google.android.gms.permission.AD_ID in the app manifest to access Ad Id.");
}
label_23:
if(((long)Build.VERSION.SDK_INT) < furq.a.e().a() || !furq.a.e().t()) {
break;
}
return b.a;
}
}
}
label_27:
amue.p(this.f);
String s1 = this.n() ? this.g() : this.h(); //没开开发者选项获取adid_key,开了开发者选项要看enable_debug_logging的值,true就是获取fake_adid_key,false是获取adid_key
return s1.isEmpty() ? this.e() : s1; //如果为空重新生成adid
}
// 判断开发者选项有没有打开,打开"development_settings_enabled"值是1 ,默认没打开是0;若==0 直接返回false, 否则返回enable_debug_logging 的值。
adb shell settings get global development_settings_enabled 可以看这个值。
public final boolean n() {
if(fuok.c()) {
try {
return Settings.Global.getInt(this.f.getContentResolver(), "development_settings_enabled", 0) == 0 ? false : this.b().getBoolean("enable_debug_logging", false);
}
catch(Exception exception0) {
Log.w("AdvertisingIdSettings", "Fail to determine debug setting.", exception0);
return false;
}
}
return false;
}
public final String g() {
return this.b().getString("fake_adid_key", "");
}
public final String h() {
return this.b().getString("adid_key", "");
}
//重新生成adid 保存到sp里面
public final String e() {
String s1;
String s;
boolean z;
Object object0 = this.b;
__monitor_enter(object0);
try {
z = this.n();
s = z ? b.d() : "";
this.j();
s1 = "";
if(!furq.j()) {
goto label_15;
}
boolean z1 = furq.a.e().Q();
}
catch(Throwable throwable0) {
goto label_26;
}
if(!z1) {
goto label_15;
}
try {
s1 = ddvs.b(this.g.e()).toString();
if(!TextUtils.isEmpty(s1)) {
goto label_15;
}
throw new IOException("Generated Id is null");
}
catch(IOException | GeneralSecurityException exception0) {
}
catch(Throwable throwable0) {
goto label_26;
}
try {
d.c(this.f, "generateNewIdError", exception0);
s1 = "";
label_15:
int v = TextUtils.isEmpty(s1);
if(v != 0) {
s1 = UUID.randomUUID().toString();
}
if(furq.a.e().A()) {
q.a(this.f).b();
q.a(this.f).c();
}
int v1 = this.b().getInt("adid_reset_count", 0) + 1;
this.b().edit().putInt("adid_reset_count", v1).apply();
__monitor_exit(object0);
return this.i(z, ((boolean)(v ^ 1)), s1, s);
label_26:
__monitor_exit(object0);
}
catch(Throwable throwable0) {
goto label_26;
}
throw throwable0;
}
public final String i(boolean z, boolean z1, String s, String s1) {
if(z) {
amdo.b(((boolean)(s1.isEmpty() ^ 1)));
}
else {
amdo.b(s1.isEmpty());
}
this.b().edit().putBoolean("enable_debug_logging", z).putBoolean("using_cert", z1).putString("adid_key", s).putString("fake_adid_key", s1).apply();
this.k();
return z ? s1 : s;
}
//fake_adid_key
public static String d() {
String s = UUID.randomUUID().toString();
return s.substring(0, s.length() - 12) + "10ca1ad1abe1";
}
//sp配置文件
final SharedPreferences b() {
return this.f.getSharedPreferences("adid_settings", 4);
}
sp配置文件的路径和内容:
sargo:/data/data/com.google.android.gms/shared_prefs # cat adid_settings.xml
<?xml version='1.0' encoding='utf-8' standalone='yes' ?>
<map>
<boolean name="enable_debug_logging" value="false" />
<boolean name="using_cert" value="false" />
<string name="adid_key">a8e3cc65-3fa2-4d07-9688-24ad61ac110d</string>
<string name="fake_adid_key"></string>
<int name="adid_reset_count" value="1" />
<boolean name="enable_limit_ad_tracking" value="false" />
</map>