专栏首页wOw的Android小站[Android][Framework]Provision

[Android][Framework]Provision

Provision是什么?

Provision的作用很简单,就是一个系统初始化引导程序,源生的Android里面Provision只做了一件事,就是写入一个DEVICE_PROVISIONED标记。

这个标记作用很大,这个标记只会在系统 全新升级(双清)的时候写入一次,代表了Android系统升级准备完成,可以正常工作。

Provision在哪?

一般在package目录下:package/apps/Provision

Proision代码

Provision下只有一个Activity文件和一个Manifest文件

Manifest

<application>
  <activity android:name="DefaultActivity"
          android:excludeFromRecents="true">
      <intent-filter android:priority="1">
          <action android:name="android.intent.action.MAIN" />
          <category android:name="android.intent.category.HOME" />
          <category android:name="android.intent.category.DEFAULT" />
      </intent-filter>
  </activity>
</application>

配置说明:

  • android:excludeFromRecents="true" 不在Recents界面显示。
  • <intent-filter android:priority="1"> 优先级高于Launcher,所以会先于Launcher启动(因为系统Launcher没有显式设置priority值,所以默认是0)
  • category.HOME 桌面程序标记,和Launcher属于一个级别

Activity

public class DefaultActivity extends Activity
{
  @Override
  protected void onCreate(Bundle icicle)
  {
      super.onCreate(icicle);

      // Add a persistent setting to allow other apps to know the device has been provisioned.
      Settings.Secure.putInt(getContentResolver(), Settings.Secure.DEVICE_PROVISIONED, 1);

      // remove this activity from the package manager.
      PackageManager pm = getPackageManager();
      ComponentName name = new ComponentName(this, DefaultActivity.class);
      pm.setComponentEnabledSetting(name, PackageManager.COMPONENT_ENABLED_STATE_DISABLED,
          PackageManager.DONT_KILL_APP);

      // terminate the activity.
      finish();
  }
}

源生代码很简单 做了两件事:

  1. 设置DEVICE_PROVISIONED标记
  2. 禁止Provision自己的Activity组件

对这个代码做点说明:

// Add a persistent setting to allow other apps to know the device has been provisioned.
Settings.Secure.putInt(getContentResolver(), Settings.Secure.DEVICE_PROVISIONED, 1);

注释表述很清楚:为设备写入持久的数据,并供其他App了解设备已经provision过。

class Settings The Settings provider contains global system-level device preferences. class Secure Secure system settings, containing system preferences that applications can read but are not allowed to write. These are for preferences that the user must explicitly modify through the system UI or specialized APIs for those values, not modified directly by applications. public static boolean putInt(ContentResolver cr, String name, int value) Convenience function for updating a single settings value as an integer. This will either create a new entry in the table if the given name does not exist, or modify the value of the existing row with that name. Note that internally setting values are always stored as strings, so this function converts the given value to a string before storing it.

  • @param cr The ContentResolver to access.
  • @param name The name of the setting to modify.
  • @param value The new value for the setting.
  • @return true if the value was set, false on database errors

禁止组件的功能

pm.setComponentEnabledSetting(name, PackageManager.COMPONENT_ENABLED_STATE_DISABLED,
    PackageManager.DONT_KILL_APP);

public abstract void setComponentEnabledSetting(ComponentName componentName, int newState, int flags); Set the enabled setting for a package component (activity, receiver, service, provider). This setting will override any enabled state which may have been set by the component in its manifest.

  • @param componentName The component to enable
  • @param newState The new enabled state for the component. The legal values for this state are:
    • COMPONENT_ENABLED_STATE_ENABLED
    • COMPONENT_ENABLED_STATE_DISABLED
    • COMPONENT_ENABLED_STATE_DEFAULT The last one removes the setting, thereby restoring the component’s state to whatever was set in it’s manifest (or enabled, by default).
  • @param flags Optional behavior flags: DONT_KILL_APP or 0.

功能禁止后,系统package信息会记录下来,保存在 /data/system/packages.xml

<package name="com.android.provision" codePath="/system/app/Provision.apk" nativeLibraryPath="/data/data/com.android.provision/lib"
flags="1" ft="11b7e237e00" it="11b7e237e00"
ut="11b7e237e00" version="15" userId="10005">
<sigs count="1">
<cert index="1" />
</sigs>
<disabled-components>
<item name="com.android.provision.DefaultActivity" />
</disabled-components>
</package>

这段代码就是记录的禁止DefaultActivity的信息。所以这个组件只会运行一次,之后就被禁止运行了。除非格式化/data/目录。

5X实现

/**
* Application that sets the provisioned bit, like SetupWizard does.
*/
public class DefaultActivity extends Activity {
  private static final String ORIGINAL_LAUNCHER_PACKAGENAME = "com.android.launcher3";
  private static final String ORIGINAL_LAUNCHER_CLASSNAME = "com.android.launcher3.Launcher";
  @Override
  protected void onCreate(Bundle icicle) {
      super.onCreate(icicle);

      // Add a persistent setting to allow other apps to know the device has been provisioned.
      Settings.Global.putInt(getContentResolver(), Settings.Global.DEVICE_PROVISIONED, 1);
      Settings.Secure.putInt(getContentResolver(), Settings.Secure.USER_SETUP_COMPLETE, 1);

      // remove this activity from the package manager.
      PackageManager pm = getPackageManager();
      ComponentName name = new ComponentName(this, DefaultActivity.class);

      pm.setComponentEnabledSetting(name, PackageManager.COMPONENT_ENABLED_STATE_DISABLED,
              PackageManager.DONT_KILL_APP);
      //set Launcher3 as the preferred home activity
      setupDefaultLauncher(pm);
      // terminate the activity.
      finish();
  }

  private void setupDefaultLauncher(PackageManager pm){
      Intent queryIntent = new Intent();
      queryIntent.addCategory(Intent.CATEGORY_HOME);
      queryIntent.setAction(Intent.ACTION_MAIN);  // 查找符合 Launcher 的 activity

      List<ResolveInfo> homeActivities = pm.queryIntentActivities(queryIntent, 0);
      if(homeActivities == null) {
          return;
      }

      ComponentName defaultLauncher = new ComponentName(ORIGINAL_LAUNCHER_PACKAGENAME,
              ORIGINAL_LAUNCHER_CLASSNAME);
      int activityNum = homeActivities.size();
      ComponentName[] set = new ComponentName[activityNum];
      int defaultMatch = -1;
      for(int i = 0; i < activityNum; i++){ //从符合 Launcher 中查找 Launcher3
          ResolveInfo info = homeActivities.get(i);
          set[i] = new ComponentName(info.activityInfo.packageName, info.activityInfo.name);
          if(ORIGINAL_LAUNCHER_CLASSNAME.equals(info.activityInfo.name)
                  && ORIGINAL_LAUNCHER_PACKAGENAME.equals(info.activityInfo.packageName)){
              defaultMatch = info.match;
          }
      }

      //if Launcher3 is not found, do not set anything
      if(defaultMatch == -1){
          return;
      }
      IntentFilter filter = new IntentFilter();
      filter.addAction(Intent.ACTION_MAIN);
      filter.addCategory(Intent.CATEGORY_HOME);
      filter.addCategory(Intent.CATEGORY_DEFAULT);

      pm.addPreferredActivity(filter, defaultMatch, set, defaultLauncher);
  }
}

Reference Android 初始化Setup Wizard——Provision

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • [Android][Framework] Android O SystemServer启动流程

    SystemServer通过ZygoteInit.java反射启动,首先会进入main方法,main会构造一个新的SystemServer,然后运行run()方...

    wOw
  • [Android][Framework]PackageManagerService处理应用权限流程

    1、system app (有ApplicationInfo.FLAG_SYSTEM标记)

    wOw
  • [Android][Framework]记一个Uri相关的奇葩bug

    那就很奇怪了,我们的系统又做了什么错事?作为负责系统的,我慌的一逼,赶紧抓一份log分析。

    wOw
  • what is telnet?

    Note: SSH is required to establish remote terminal connections to Indiana Univer...

    ke1th
  • 混合临界系统的任务级和系统级调度模式的组合(CS OS)

    针对混合临界系统,本文提出了不同的调度算法。这些算法的共同点是,当高临界任务缺乏计算资源时,就会丢弃低临界任务。这是通过将调度模式从正常模式切换到临界模式来实现...

    非过度曝光
  • 【云端起舞】Oracle云上一键安装数据库补丁集

    编辑手记:为数据库升级打补丁是一项常规的任务,在通常情况下 ,打补丁是一件繁琐的事情,需要考虑的细节比较多。但在云上,可以通过按钮一键式应用 相关补丁集,高效便...

    数据和云
  • SAP CRM Enterprise Search initial load遇到错误该如何处理

    Web Dynpro Transaction: ESH_ADMIN_UI_COMPONENT

    Jerry Wang
  • Set up development environment for apps for SharePoint 2013

    SharePoint 2013 support app development pattern.An app for SharePoint is small ...

    用户1161731
  • 用schemaSpy制作数据库文档

    Schemaspy是一款Java开发的数据库文档生成工具,是开源的。生成的数据库文档非常的漂亮,实用。最近探索了两天终于会使用这个工具了。我接触到这个工具是在开...

    张善友
  • FSWD_BootStrap

    Course Overview 响应式设计 grid system CSS Button Form Tables panel well image media ...

    用户1147754

扫码关注云+社区

领取腾讯云代金券