Android暗码启动应用程序

ProductInfo应用分析

ProductInfo结构:

在这里插入图片描述
①AndroidManifest.xml
 为应用的 Java 软件包命名。软件包名称充当应用的唯一标识符。
 描述应用的各个组件,包括构成应用的 Activity、服务、广播接收器和内容提供程序。它还为实现每个组件的类命名并发布其功能,例如它们可以处理的 Intent 消息。这些声明向 Android 系统告知有关组件以及可以启动这些组件的条件的信息。
 确定托管应用组件的进程。
 声明应用必须具备哪些权限才能访问 API 中受保护的部分并与其他应用交互。还声明其他应用与该应用组件交互所需具备的权限
 声明应用所需的最低 Android API 级别
 列出应用必须链接到的库
这个应用比较特殊,因为没有声明,所以安装完成后没有图标和默认的启动界面
此应用是通过声明的广播接收者:.SecretCode监听特定的action进行启动特定的activity界面
②BroadcastReceiver实现类
实现当接收到广播发送者发送的信息时,响应具体的代码逻辑,这里是通过判断分析广播发送者发送的不同暗码信息,响应不同的activity。
③activity实现类
四个activity实现具体的打开展示界面,这里的activity主要通过不同的暗码,加载不同的布局文件,然后在代码中从外部不同的设备信息文件中,抓取需要的设备信息,填充到相应的布局块中进行显示。
④资源文件
首先就是xml文件夹下面的各种页面的布局文件,这些文件定义了最终的呈现布局,然后通过加载values文件夹里面的string.xml,填充布局文件定义的不同初始化字段。
⑤Android.mk
Android不同模块的编译文件,在此文件中义了不同的编译脚本信息,指定以何种方式编译模块。
⑥其他
诸如图标、图片文件夹drawable、activity布局文件夹layout等

ProductInfo启动运行过程分析

因为此应用没有图标和默认的启动界面,是通过广播接收者,监听特定的广播进而启动不同的activity。
①首先/packages/apps/Dialer/java/com/android/dialer/app/SpecialCharSequenceMgr.java

  static boolean handleSecretCode(Context context, String input) {
    // Secret codes are accessed by dialing *#*#<code>#*#*
    int len = input.length();
    if (len <= 8 || !input.startsWith("*#*#") || !input.endsWith("#*#*")) {
      return false;
    }
    String secretCode = input.substring(4, len - 4);
    TelephonyManagerCompat.handleSecretCode(context, secretCode);
    return true;
  }

handleSecretCode方法对输入的暗码进行解析,然后执行TelephonyManagerCompat.handleSecretCode方法。
②/packages/apps/Dialer/java/com/android/contacts/common/compat/TelephonyManagerCompat.java

private static final String SECRET_CODE_ACTION = "android.provider.Telephony.SECRET_CODE";
public static void handleSecretCode(Context context, String secretCode) {
    // Must use system service on O+ to avoid using broadcasts, which are not allowed on O+.
    if (BuildCompat.isAtLeastO()) {
      if (!TelecomUtil.isDefaultDialer(context)) {
        LogUtil.e(
            "TelephonyManagerCompat.handleSecretCode",
            "not default dialer, cannot send special code");
        return;
      }
      context.getSystemService(TelephonyManager.class).sendDialerSpecialCode(secretCode);
    } else {
      // System service call is not supported pre-O, so must use a broadcast for N-.
      Intent intent =
          new Intent(SECRET_CODE_ACTION, Uri.parse("android_secret_code://" + secretCode));
      context.sendBroadcast(intent);
    }
  }

此方法通过发送一条SECRET_CODE_ACTION,并携带Uri数据形式的广播,把消息传播出去。
③AndroidManifest.xml中注册的广播接收者.SecretCode响应监听到的SECRET_CODE_ACTION这条广播。

<receiver android:name=".SecretCode">
        	<intent-filter>
        		<action android:name="android.provider.Telephony.SECRET_CODE"/>
        		<data android:scheme="android_secret_code" android:host="74657799" />
                。。。。。。
        	</intent-filter>
 </receiver>

广播接收者SecretCode接收到SECRET_CODE_ACTION这条广播,并对定义的data数据相匹配,如果匹配成功则进入SecretCode这个实现类中执行相应的的方法。
④广播接收者SecretCode.java实现类

    @Override
    public void onReceive(Context context, Intent intent) {
        if (intent.getAction().equals(SECRET_CODE_ACTION)) {
            final String SECRET_CODE_ACTION = "android_secret_code://";
            Uri uri = intent.getData();
            String str = null;
            if (uri != null) {
                str = uri.toString().substring(SECRET_CODE_ACTION.length(), uri.toString().length());}
            if("74657799".equals(str)) {
                try { Intent i = new Intent("action.com.tnmb.productinfo.VersionInfo");
                    i.putExtra("edit_input", "*#*#" + str + "#*#*");
                    i.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); // must
                    context.startActivity(i);
                } catch (Exception e) {android.util.Log.d("InfoProject", "uri = " + uri.toString() + "; str = " + str);}}
              。。。。。。
     }

通过监听到的不同暗码,通过Intent隐式启动action.com.tnmb.productinfo.VersionInfo这个activity
⑤VersionInfo.java,activity实现类

@Override
    public void onCreate(Bundle icicle) {
        super.onCreate(icicle);
        Bundle extras = getIntent().getExtras();
        if(extras != null){
            String input = extras.getString("edit_input");}
if (input.startsWith("*#*#563412") && input.endsWith("#*#*")) {
                Log.e(LOG_TAG, "WikoVersionInfo:onCreate");
                addPreferencesFromResource(R.xml.wiko_de_version_info);
                setValueSummary(KEY_WIKO_VERSION, "ro.tcustom.build.version");  }
            。。。。。。
      }

VersionInfo类通过Intent传递的不同暗码加载不同的布局文件如R.xml.wiko_de_version_info,然后在系统中获取需要显示的设备信息,通过setValueSummary()方法设置到最终显示的布局页面上。
ProductInfo其他activity页面启动过程与上述大同小异。

模块添加编译过程
①./Android.mk
②tinno/component/config/apps_config.mk:4:PRODUCT_PACKAGES += ProductInfo
③device/sprd/pike2/k121/k121.mk:447:include vendor/tinno/component/config/apps_config.mk

ProductInfo优化与改进

①代码冗余太多,对于没有使用的暗码和代码,应该及时删除,避免在分析代码的时候引起歧义混淆,还有就是暗码规范,不能随意使用特定系统暗码,如:06,查看IMEI号暗码。
②因为监听的是系统广播发送者发送的action,而系统发送的是无序广播,所以当外部广播接收者监听到相同字段的暗码的时候,会同时响应。所以最好自己实现暗码的监听,发送有序广播,在接收到广播后,阻断其传播,避免广播的混乱。
③暗码太多,在没有使用文档的帮助下,很难知道具体的暗码,并且对应的页面具体显示的是什么设备信息。所以可以设置一个统一入口界面,分门别类的建立各个子页面,一目了然,而不是输入一大堆记不住的暗码。

发布了25 篇原创文章 · 获赞 0 · 访问量 588

猜你喜欢

转载自blog.csdn.net/u011609120/article/details/103873510