前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >[Android][Framework]Provision

[Android][Framework]Provision

作者头像
wOw
发布2018-09-18 15:21:12
2K0
发布2018-09-18 15:21:12
举报
文章被收录于专栏:wOw的Android小站wOw的Android小站

Provision是什么?

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

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

Provision在哪?

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

Proision代码

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

Manifest
代码语言:javascript
复制
<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
代码语言:javascript
复制
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组件

对这个代码做点说明:

代码语言:javascript
复制
// 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

禁止组件的功能

代码语言:javascript
复制
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

代码语言:javascript
复制
<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实现

代码语言:javascript
复制
/**
* 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

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2016-10-28,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • Provision是什么?
  • Provision在哪?
  • Proision代码
    • Manifest
      • Activity
      • 5X实现
      领券
      问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档