CTS延長--マスター・ユーザーと管理対象ユーザー(Managed Profile)
30717 ワード
CTS延長--マスター・ユーザーと管理対象ユーザー(Managed Profile)
0.起因
CtsVerifierテストを行ったところ、「Cross profile intent filters are set」の手動検証に失敗したことがわかりました.ログを見ると以下のようになります.
10:46:45.111 10694 10694 E IntentFiltersTestHelper: Intent { act=android.intent.action.DIAL dat=tel:xxx } from managed profile should be forwarded to the primary profile but is not.
08-11 10:46:45.120 10694 10694 E IntentFiltersTestHelper: Intent { act=android.intent.action.VIEW cat=[android.intent.category.BROWSABLE] dat=tel:xxx } from managed profile should be forwarded to the primary profile but is not.
08-11 10:46:45.145 10694 10694 E IntentFiltersTestHelper: Intent { act=android.intent.action.DIAL dat=tel:xxx } from managed profile should be forwarded to the primary profile but is not.
08-11 10:46:45.148 10694 10694 E IntentFiltersTestHelper: Intent { act=android.intent.action.VIEW cat=[android.intent.category.BROWSABLE] dat=tel:xxx } from managed profile should be forwarded to the primary profile but is not.
08-11 10:46:45.174 10694 10694 E IntentFiltersTestHelper: Intent { act=android.intent.action.DIAL dat=tel:xxx } from managed profile should be forwarded to the primary profile but is not.
08-11 10:46:45.177 10694 10694 E IntentFiltersTestHelper: Intent { act=android.intent.action.VIEW cat=[android.intent.category.BROWSABLE] dat=tel:xxx } from managed profile should be forwarded to the primary profile but is not.
managed profileからprimary profileに転送されるはずのIntent{act=android.intent.action.DIAL dat=tel:xxx}が送信されますが、転送されません.
このとき、managed profileとprimary profileがそれぞれ何なのか分からないので、原因を特定できません.
ソースコードを読んでログを追加し、CTS-Vを再編成した後、検証手順は大体以下の通りであることが分かった.
Intent{act=android.intent.action.DIAL dat=tel:xxx}は私たちのDialtactsActivityに一致する位置しか特定できないため、CTS検証は失敗で終了します.失敗の原因は分かっていたのですが、なぜこのように検証するのか分からず、この文章ができました.
1.ユーザー(Primary profile)と管理対象ユーザー(Managed profile)
特定のユーザのタイプは、ソースコードのUserInfoのFLAG_を表示することによってXXXXXの解釈は、ここに必要ないくつかをリストします.
アプリケーションとユーザの関係は,uid,userId,appIdの3つの関係であり,ソースコードのProcessとUserHandleを表示することで得られる.
2.設備管理権限の申請
2ステップでデバイス管理権限を取得できます.
1.デバイス管理権限の申請要求を送信します.
private void provisionManagedProfile() {
Activity activity = getActivity();
if (null == activity) {
return;
}
//
Intent intent = new Intent(DevicePolicyManager.ACTION_PROVISION_MANAGED_PROFILE);
// Use a different intent extra below M to configure the admin component.
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {
//noinspection deprecation
// M , , DeviceReceiver,
// DeviceReceiver
intent.putExtra(DevicePolicyManager.EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_NAME,
activity.getApplicationContext().getPackageName());
} else {
// M ,
final ComponentName component = new ComponentName(activity,
BasicDeviceAdminReceiver.class.getName());
intent.putExtra(DevicePolicyManager.EXTRA_PROVISIONING_DEVICE_ADMIN_COMPONENT_NAME,
component);
}
if (intent.resolveActivity(activity.getPackageManager()) != null) {
// onActivityResult / 。
startActivityForResult(intent, REQUEST_PROVISION_MANAGED_PROFILE);
activity.finish();
} else {
Toast.makeText(activity, "Device provisioning is not enabled. Stopping.",
Toast.LENGTH_SHORT).show();
}
}
2.権限の受信およびプロファイルの設定が可能です.
受信権限はDeviceAdminReceiverの宣言を引き継いだManifestのReceiverである必要があります.
<receiver
android:name=".BasicDeviceAdminReceiver"
android:description="@string/app_name"
android:label="@string/app_name"
<!-- android.permission.BIND_DEVICE_ADMIN -->
android:permission="android.permission.BIND_DEVICE_ADMIN">
<meta-data
android:name="android.app.device_admin"
android:resource="@xml/basic_device_admin_receiver"/>
<intent-filter>
<action android:name="android.app.action.DEVICE_ADMIN_ENABLED"/>
</intent-filter>
</receiver>
basic_device_admin_receiver.xmlファイルの内容
<device-admin>
<!-- -->
<uses-policies>
<limit-password/>
<watch-login/>
<reset-password/>
<force-lock/>
<wipe-data/>
<expire-password/>
<encrypted-storage/>
<disable-camera/>
<disable-keyguard-features/>
</uses-policies>
</device-admin>
public class BasicDeviceAdminReceiver extends DeviceAdminReceiver {
// ,onProfileProvisioningComplete 。
// Receiver ManagedProfile.
// Profile disable 。
@Override
public void onProfileProvisioningComplete(Context context, Intent intent) {
Intent launch = new Intent(context, EnableProfileActivity.class);
launch.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
context.startActivity(launch);
}
}
現在のプロファイルをEnableProfileActivityでEnabled状態に設定し、ユーザー名を設定します.
private void enableProfile() {
DevicePolicyManager manager =
(DevicePolicyManager) getSystemService(Context.DEVICE_POLICY_SERVICE);
ComponentName componentName = BasicDeviceAdminReceiver.getComponentName(this);
// This is the name for the newly created managed profile.
manager.setProfileName(componentName, getString(R.string.profile_name));
// We enable the profile here.
manager.setProfileEnabled(componentName);
}
これで、デバイス管理権限を申請する手順が完了し、セットアップ->スクリーンロック、指紋、セキュリティ->より多くのセキュリティ設定->デバイスマネージャでアプリケーションを表示できます.設定->アカウントには、作業アカウントが表示されます.
デスクトップに戻ると、Profileユーザーに属する右下にパケット付きのアプリケーションが追加されています.デフォルトでは、Googleは基本的なユーザー体験を保証するアプリケーションを追加します.
3.マスターユーザと管理されたユーザとの間の通信
現在、我々のデバイスでは2人のユーザが実行されており、現在実行されているユーザ情報を
adb shell pm list users
でリストすることができます.Users:
UserInfo{0: :13} running
UserInfo{12: :30} running
安全のため、Androidはデフォルトでプライマリ・ユーザーとManagedProfile間の通信を完全に分離しています.ただし、デバイス管理者は、特定のIntentFilterチャネルを開くこともできます.Androidコンポーネント間の通信は主にIntentによって行われ、マッチングルールは主にintent-filter項目に定義されていることが知られています.次に、IntentFilterチャネルを開く例を示します.
private void enableForwarding() {
Activity activity = getActivity();
if (null == activity || activity.isFinishing()) {
return;
}
DevicePolicyManager manager =
(DevicePolicyManager) activity.getSystemService(Context.DEVICE_POLICY_SERVICE);
try {
IntentFilter filter = new IntentFilter(Intent.ACTION_SEND);
filter.addDataType("text/plain");
filter.addDataType("image/jpeg");
// This is how you can register an IntentFilter as allowed pattern of Intent forwarding
manager.addCrossProfileIntentFilter(BasicDeviceAdminReceiver.getComponentName(activity),
filter, FLAG_MANAGED_CAN_ACCESS_PARENT | FLAG_PARENT_CAN_ACCESS_MANAGED);
} catch (IntentFilter.MalformedMimeTypeException e) {
e.printStackTrace();
}
}
ACTION_をSENDというActionはCrossProfile IntentFilterに追加され、Profileユーザー環境下でこのActionを送信するのは応答しません.
ProfileユーザーにもレスポンスACTIONがインストールされていない限りSENDの応用.
内
:Profileユーザー間で送信できるIntentのターゲットコンポーネントはActivityである必要があります.4.マスター・ユーザーの下にあるAPPをManagedProfileユーザーにインストールし、一部のコンポーネントを無効にします。
private void setAppEnabled(String packageName, boolean enabled) {
Activity activity = getActivity();
if (null == activity) {
return;
}
PackageManager packageManager = activity.getPackageManager();
DevicePolicyManager devicePolicyManager =
(DevicePolicyManager) activity.getSystemService(Context.DEVICE_POLICY_SERVICE);
try {
int packageFlags;
if(Build.VERSION.SDK_INT < 24){
//noinspection deprecation
packageFlags = PackageManager.GET_UNINSTALLED_PACKAGES;
}else{
packageFlags = PackageManager.MATCH_UNINSTALLED_PACKAGES;
}
ApplicationInfo applicationInfo = packageManager.getApplicationInfo(packageName,
packageFlags);
// Here, we check the ApplicationInfo of the target app, and see if the flags have
// ApplicationInfo.FLAG_INSTALLED turned on using bitwise operation.
//
if (0 == (applicationInfo.flags & ApplicationInfo.FLAG_INSTALLED)) {
// If the app is not installed in this profile, we can enable it by
// DPM.enableSystemApp
if (enabled) {
// APP 。
devicePolicyManager.enableSystemApp(
BasicDeviceAdminReceiver.getComponentName(activity), packageName);
} else {
// But we cannot disable the app since it is already disabled
Log.e(TAG, "Cannot disable this app: " + packageName);
return;
}
} else {
// If the app is already installed, we can enable or disable it by
// DPM.setApplicationHidden
// APP, APP 。
devicePolicyManager.setApplicationHidden(
BasicDeviceAdminReceiver.getComponentName(activity), packageName, !enabled);
}
Toast.makeText(activity, enabled ? R.string.enabled : R.string.disabled,
Toast.LENGTH_SHORT).show();
} catch (PackageManager.NameNotFoundException e) {
Log.e(TAG, "The app cannot be found: " + packageName, e);
}
}
場合によっては、ManagedProfileユーザーで一部のAPPを禁止したり、コンポーネントを禁止したりする必要があります.
//
context.getPackageManager().setComponentEnabledSetting(componentName,
PackageManager.COMPONENT_ENABLED_STATE_DISABLED, 0);
//
context.getPackageManager().setApplicationEnabledSetting(context.getPackageName(),
PackageManager.COMPONENT_ENABLED_STATE_ENABLED, 0);
コンポーネントが無効になると、明示的であれ暗黙的であれ、コンポーネントに一致しません.
5.以上のCTSテストの原理及び解決方案
「Cross profile intent filters are set」は、実際にaddCross Profile IntentFilterで対応するIntent Filtersが設定されているかどうかをテストすることであることがわかります.
上記の失敗した情報は、実際にはManaged profileからIntentを発行した後、ユーザー間で応答できるはずだったが、そうではなかった.これは、対応するIntent Filterがユーザー間で応答できるように設定されていないことをさらに示している.
ただし、addCrossProfileIntentFilterは管理者権限を持つDeviceAdminReceiverコンポーネントを提供する必要があるため、アプリケーションで直接設定することはできません.
テストの結果、アプリケーションパッケージ名が
packages/apps/ManagedProvisioning/res/values/vendor_required_apps_managed_profile.xml
に追加された場合、対応するアプリケーションはProfileの設定が完了した後、Managed profileユーザースペースにデフォルトでインストールされることが分かった.これにより、アプリケーションのIntent Filterがユーザー間で設定されなくなります.従って、ユーザが初期化されたときに、ユーザFLAGSに基づいてアプリケーションが利用可能か否かを設定することができる.私たちの目的は、電話アプリケーションをManged Profileの下で使用できないようにすることです.CTSテストもManged Profileユーザーを作成してテストするため、完全に正確ではないことを確認します.その後、具体的なFLAGSに基づいてCTSテストとCTS-Vテストを区別し、最終的にテストに合格した.具体コード
権限(システムアプリケーションのみが申請できます)
<uses-permission android:name="android.permission.MANAGE_USERS"/>
// Receiver
<receiver android:name="com.tplink.dialer.BootCompletedReceiver">
<intent-filter>
<action android:name="android.intent.action.USER_INITIALIZE" />
</intent-filter>
</receiver>
UserInfoという原生は隠れていてSDKがオープンしているのでそのまま使えます.
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if(action.equals(Intent.ACTION_USER_INITIALIZE)) {
if (UserHandle.myUserId() != 0) {
/* , UserInfo.isEnable(),
* Cts-V isEnable() false, CTS true.
* Cts-V , CTS 。
*/
UserManager um = UserManager.get(context);
UserInfo currentUserInfo = um.getUserInfo(UserHandle.myUserId());
log("current user " + currentUserInfo);
if (currentUserInfo.isEnabled()) {
//
context.getPackageManager().setApplicationEnabledSetting(context.getPackageName(),
PackageManager.COMPONENT_ENABLED_STATE_ENABLED, 0);
} else {
//
context.getPackageManager().setApplicationEnabledSetting(context.getPackageName(),
PackageManager.COMPONENT_ENABLED_STATE_DISABLED, 0);
}
}
}
}
本明細書で適用されるコードの大部分は、次のとおりです.https://github.com/googlesamples/android-BasicManagedProfile
転載先:https://github.com/shiwen500/jenkinsTest