[DESCRIPTION]
由于目前所有的手机都要求支持Android for work, 客户在测试CTS,GTS过程中,经常在profile_provisioning的过程中出错,这边对经常出错的地方进行分析,并提供对应的解决方案
[SOLUTION]
其中就以GTS测试中testProvision这个测试fail为例分析profile_provisioning的流程
一般遇到的fail log为
1 2 3 4 5 6 7 |
Line 6051: 07-30 17:59:42.467 19495 19510 I TestRunner: failed: testProvision(com.google.android.gts.managedprovisioning.ManagedProfileProvisioningTest) Line 6052: 07-30 17:59:42.467 19495 19510 I TestRunner: ----- begin exception ----- Line 6053: 07-30 17:59:42.467 19495 19510 I TestRunner: java.lang.AssertionError Line 6054: 07-30 17:59:42.467 19495 19510 I TestRunner: at org.junit.Assert.fail(Assert.java:86) Line 6055: 07-30 17:59:42.467 19495 19510 I TestRunner: at org.junit.Assert.assertTrue(Assert.java:41) Line 6056: 07-30 17:59:42.467 19495 19510 I TestRunner: at org.junit.Assert.assertTrue(Assert.java:52) Line 6057: 07-30 17:59:42.467 19495 19510 I TestRunner: at com.google.android.gts.managedprovisioning.ManagedProfileProvisioningTest.testProvision(ManagedProfileProvisioningTest.java:54) |
1.ManagedProfileProvisioningTest.java中call
1 2 3 4 5 6 7 8 9 10 |
SilentProvisioningTestManager.startProvisioningAndWait() public void testProvision() throws InterruptedException { Intent localIntent = new Intent("android.app.action.PROVISION_MANAGED_PROFILE").putExtra("android.app.extra.PROVISIONING_DEVICE_ADMIN_COMPONENT_NAME", GtsAdminReceiver.getComponentName(this.mContext)).putExtra("android.app.extra.PROVISIONING_SKIP_ENCRYPTION", true); SilentProvisioningTestManager localSilentProvisioningTestManager = new SilentProvisioningTestManager(this.mContext); Assert.assertTrue(localSilentProvisioningTestManager.startProvisioningAndWait(localIntent)); Assert.assertTrue(isExtraUserPresent(localSilentProvisioningTestManager.getReceviedProfileProvisionedIntent())); } } |
2.startProvisioningAndWait ()这个方法:
a.启动PreProvisioningActivity去provisioning
b.等待broadcast-ACTION_MANAGED_PROFILE_PROVISIONED ,timeout为10s
c.如果10s没有等到broadcast,那么就return null,就会打出error log:
SilentProvisioningTest:managedProfileProvisionedReceiver.awaitForBroadcast(): failed");
xref: /cts/common/device-side/util/src/com/android/compatibility/common/util/devicepolicy/provisioning/SilentProvisioningTestManager.java
1 2 3 4 5 6 7 8 9 10 11 |
public boolean startProvisioningAndWait(Intent provisioningIntent) throws InterruptedException { 67 wakeUpAndDismissInsecureKeyguard(); 68 mContext.startActivity(getStartIntent(provisioningIntent)); //a.此处会start PreProvisioningActivity 69 Log.i(TAG, "startActivity with intent: " + provisioningIntent); 70 71 if (ACTION_PROVISION_MANAGED_PROFILE.equals(provisioningIntent.getAction())) { 72 return waitManagedProfileProvisioning(); //b. 等待broadcast-ACTION_MANAGED_PROFILE_PROVISIONED,timeout为10s 73 } else { 74 return waitDeviceOwnerProvisioning(); 75 } 76 } |
3.waitManagedProfileProvisioning()这个方法:
a.注册ACTION_MANAGED_PROFILE_PROVISIONED和ACTION_MANAGED_PROFILE_ADDED的BroadcastReceiver
b.调用pollProvisioningResult() check profile_provisioning是否有完成,即是否有接到ACTION_PROFILE_PROVISIONING_COMPLETE的broadcast,timeout为120s
c.如果120s之后没有等待broadcast,pollProvisioningResult()==false,就会打出error log:
SilentProvisioningTest: ManagedProvisioning doesn't return result within 120 seconds
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 |
private boolean waitManagedProfileProvisioning() throws InterruptedException { 83 BlockingBroadcastReceiver managedProfileProvisionedReceiver = 84 new BlockingBroadcastReceiver(mContext, ACTION_MANAGED_PROFILE_PROVISIONED); 85 BlockingBroadcastReceiver managedProfileAddedReceiver = 86 new BlockingBroadcastReceiver(mContext, ACTION_MANAGED_PROFILE_ADDED); 87 try { 88 managedProfileProvisionedReceiver.register(); //a.注册ACTION_MANAGED_PROFILE_PROVISIONED的BroadcastReceiver 89 managedProfileAddedReceiver.register(); //a.注册ACTION_MANAGED_PROFILE_ADDED的BroadcastReceiver 90 91 if (!pollProvisioningResult()) { //b.检查是否有完成profile_provisioning,即是否有接到ACTION_PROFILE_PROVISIONING_COMPLETE的broadcast 92 return false; 93 } 94 95 mReceivedProfileProvisionedIntent = 96 managedProfileProvisionedReceiver.awaitForBroadcast(); //2.b等待broadcast-ACTION_MANAGED_PROFILE_PROVISIONED,timeout=10s 97 if (mReceivedProfileProvisionedIntent == null) { 98 Log.i(TAG, "managedProfileProvisionedReceiver.awaitForBroadcast(): failed"); //2.c 10s之内没有收到broadcast,就会fail 99 return false; 100 } 101 102 if (managedProfileAddedReceiver.awaitForBroadcast() == null) { 103 Log.i(TAG, "managedProfileAddedReceiver.awaitForBroadcast(): failed"); 104 return false; 105 } 106 } finally { 107 managedProfileProvisionedReceiver.unregisterQuietly(); 108 managedProfileAddedReceiver.unregisterQuietly(); 109 } 110 return true; 111 } |
4.pollProvisioningResult() 方法:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
private boolean pollProvisioningResult() throws InterruptedException { 114 Boolean result = mProvisioningResults.poll(TIMEOUT_SECONDS, TimeUnit.SECONDS); //3.b是否有接到ACTION_PROFILE_PROVISIONING_COMPLETE的broadcast,timeout为120s 115 if (result == null) { 116 Log.i(TAG, "ManagedProvisioning doesn't return result within " 117 + TIMEOUT_SECONDS + " seconds "); //3.c 120s没有收到就会fail 118 return false; 119 } 120 121 if (!result) { 122 Log.i(TAG, "Failed to provision"); 123 return false; 124 } 125 return true; 126 } |
5. ACTION_PROFILE_PROVISIONING_COMPLETE这个broadcast要在ACTION_MANAGED_PROFILE_PROVISIONED这个broadcast之前,当profile_provisioning完成之后,DpcReceivedSuccessReceiver就会发送这个ACTION_MANAGED_PROFILE_PROVISIONED broadcast,具体代码流程如下:
xref: /packages/apps/ManagedProvisioning/src/com/android/managedprovisioning/finalization/DpcReceivedSuccessReceiver.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
public void onReceive(Context context, Intent intent) { 66 ProvisionLogger.logd("ACTION_PROFILE_PROVISIONING_COMPLETE broadcast received by mdm");//收到provisioning_complete的broadcast的log 67 68 final Intent primaryProfileSuccessIntent = new Intent(ACTION_MANAGED_PROFILE_PROVISIONED); 69 primaryProfileSuccessIntent.setPackage(mMdmPackageName); 70 primaryProfileSuccessIntent.addFlags(Intent.FLAG_INCLUDE_STOPPED_PACKAGES | 71 Intent.FLAG_RECEIVER_FOREGROUND); 72 primaryProfileSuccessIntent.putExtra(Intent.EXTRA_USER, mManagedUserHandle); 73 74 // Now cleanup the primary profile if necessary 75 if (mMigratedAccount != null) { 76 primaryProfileSuccessIntent.putExtra(EXTRA_PROVISIONING_ACCOUNT_TO_MIGRATE, 77 mMigratedAccount); 78 finishAccountMigration(context, primaryProfileSuccessIntent); 79 // Note that we currently do not check if account migration worked 80 } else { 81 context.sendBroadcast(primaryProfileSuccessIntent); //发送ACTION_MANAGED_PROFILE_PROVISIONED的broadcast 82 } 83 } |
1 2 3 4 5 6 7 8 9 10 11 12 13 |
85 private void finishAccountMigration(final Context context, 86 final Intent primaryProfileSuccessIntent) { 87 new AsyncTask<Void, Void, Void>() { 88 @Override 89 protected Void doInBackground(Void... params) { 90 if (!mKeepAccountMigrated) { 91 mUtils.removeAccount(context, mMigratedAccount); 92 } 93 context.sendBroadcast(primaryProfileSuccessIntent); //发送ACTION_MANAGED_PROFILE_PROVISIONED的broadcast 94 return null; 95 } 96 }.execute(); 97 } |
总结,Provisioning的过程就是通过PROVISION_MANAGED_PROFILE这个intent叫起PreProvisioningActivity,然后开始provisioning,并且等待ACTION_PROFILE_PROVISIONING_COMPLETE这个广播,这个广播被接收后,会send ACTION_MANAGED_PROFILE_PROVISIONED的广播,最终完成整个provisioning流程。
测试OK的log:
Line 5253: 07-25 07:58:57.450 12762 12797 I SilentProvisioningTest: startActivity with intent: Intent { act=android.app.action.PROVISION_MANAGED_PROFILE (has extras) }
Line 5297: 07-25 07:58:57.517 12762 12762 I StartProvisionActivity: result callback class name com.android.compatibility.common.util.devicepolicy.provisioning.SilentProvisioningTestManager$1@92ca4a
Line 40624: 07-25 08:02:15.531 16286 16286 D ManagedProvisioning: ACTION_PROFILE_PROVISIONING_COMPLETE broadcast received by mdm
当cts,gts fail之后,可以通过adb shell dumpsys activity log x on或者将ActivityManagerServiceConfig.java中的DEBUG_ALL=true 打开ams debug开关,根据流程排查,看到底log指向的是provisioning中的哪个部分。
其中目前客户遇见最多的就是因为没有在规定时间内接收到广播,有时候的现象就是概率性通过。
此时:
1.首先先确认测试时使用的是user load
2.可以在打开ams debug之后的测试device_logcat_test的log中以broadcasts为关键字,看是否是因为广播太多,造成拥堵,致使广播未能及时接收到
solution: 去掉设备中预制的过多的apk,将未接收到的broadcast在ams中变成前台广播。
针对O版本,将某个broadcast变成前台广播的方法如下:
以Broadcast sticky为关键字,
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 |
final int broadcastIntentLocked(ProcessRecord callerApp, String callerPackage, Intent intent, String resolvedType, IIntentReceiver resultTo, int resultCode, String resultData, Bundle resultExtras, String[] requiredPermissions, int appOp, Bundle bOptions, boolean ordered, boolean sticky, int callingPid, int callingUid, int userId) { intent = new Intent(intent); final boolean callerInstantApp = isInstantApp(callerApp, callerPackage, callingUid); // Instant Apps cannot use FLAG_RECEIVER_VISIBLE_TO_INSTANT_APPS if (callerInstantApp) { intent.setFlags(intent.getFlags() & ~Intent.FLAG_RECEIVER_VISIBLE_TO_INSTANT_APPS); } // By default broadcasts do not go to stopped apps. intent.addFlags(Intent.FLAG_EXCLUDE_STOPPED_PACKAGES); //add here--by MTK------------------begin if (intent.getAction() != null && (intent.getAction().equals("想要变成前台广播的broadcast名称") )) { //例如:android.intent.action.LOCKED_BOOT_COMPLETED intent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND); } //add here---by MTK-----------------end // If we have not finished booting, don't allow this to launch new processes. if (!mProcessesReady && (intent.getFlags()&Intent.FLAG_RECEIVER_BOOT_UPGRADE) == 0) { intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY); } if (DEBUG_BROADCAST_LIGHT) Slog.v(TAG_BROADCAST, (sticky ? "Broadcast sticky: ": "Broadcast: ") + intent + " ordered=" + ordered + " userid=" + userId); if ((resultTo != null) && !ordered) { Slog.w(TAG, "Broadcast " + intent + " not ordered but result callback requested!"); } |
3.当然也有时候并不是因为太多广播堵塞造成,而是因为是low_ram的项目,客制化了services/core/java/com/android/server/am/ActivityManagerConstants.java中MAX_CACHED_PROCESSES造成系统更加激进的kill process。
该MAX_CACHED_PROCESSES默认为32