前言
测试这两天给我提了一个BUG,说把APK放内部储存里面,然后点击安装的时候,软件安装包程序停止运行!纳尼!原生的啊。我肯定没有动过
07-01 17:43:29.120 3257 3295 E AndroidRuntime: FATAL EXCEPTION: InstallThread
07-01 17:43:29.120 3257 3295 E AndroidRuntime: Process: com.android.packageinstaller, PID: 3257
07-01 17:43:29.120 3257 3295 E AndroidRuntime: java.lang.NullPointerException: Attempt to invoke virtual method 'void android.app.AppOpsManager.checkPackage(int, java.lang.String)' on a null object reference
07-01 17:43:29.120 3257 3295 E AndroidRuntime: at android.os.Parcel.readException(Parcel.java:1690)
07-01 17:43:29.120 3257 3295 E AndroidRuntime: at android.os.Parcel.readException(Parcel.java:1637)
07-01 17:43:29.120 3257 3295 E AndroidRuntime: at android.content.pm.IPackageInstaller$Stub$Proxy.createSession(IPackageInstaller.java:249)
07-01 17:43:29.120 3257 3295 E AndroidRuntime: at android.content.pm.PackageInstaller.createSession(PackageInstaller.java:297)
07-01 17:43:29.120 3257 3295 E AndroidRuntime: at com.android.packageinstaller.InstallAppProgress.doPackageStage(InstallAppProgress.java:295)
07-01 17:43:29.120 3257 3295 E AndroidRuntime: at com.android.packageinstaller.InstallAppProgress.-wrap2(InstallAppProgress.java)
07-01 17:43:29.120 3257 3295 E AndroidRuntime: at com.android.packageinstaller.InstallAppProgress$5.run(InstallAppProgress.java:396)
07-01 17:43:29.120 3257 3295 E AndroidRuntime: at android.os.Handler.handleCallback(Handler.java:836)
07-01 17:43:29.120 3257 3295 E AndroidRuntime: at android.os.Handler.dispatchMessage(Handler.java:103)
07-01 17:43:29.120 3257 3295 E AndroidRuntime: at android.os.Looper.loop(Looper.java:203)
07-01 17:43:29.120 3257 3295 E AndroidRuntime: at android.os.HandlerThread.run(HandlerThread.java:61)
z
分析
撸起袖子改BUG,对于程序员而言,这还得了啊,对于用户也是体验极差的
1.可以看到报错地方时在createSession的时候出错了。跟踪代码就是PackageInstallerService.java中的createSession 在具体点就是
java.lang.NullPointerException: Attempt to invoke virtual method 'void android.app.AppOpsManager.checkPackage(int, java.lang.String)' on a null object reference
这一段。然后我们在
private int createSessionInternal(SessionParams params, String installerPackageName, int userId)
throws IOException {
final int callingUid = Binder.getCallingUid();
mPm.enforceCrossUserPermission(callingUid, userId, true, true, "createSession");
if (mPm.isUserRestricted(userId, UserManager.DISALLOW_INSTALL_APPS)) {
throw new SecurityException("User restriction prevents installing");
}
if ((callingUid == Process.SHELL_UID) || (callingUid == Process.ROOT_UID)) {
params.installFlags |= PackageManager.INSTALL_FROM_ADB;
} else {
mAppOps.checkPackage(callingUid, installerPackageName);//这里打LOG看看是哪个空指针了
params.installFlags &= ~PackageManager.INSTALL_FROM_ADB;
params.installFlags &= ~PackageManager.INSTALL_ALL_USERS;
params.installFlags |= PackageManager.INSTALL_REPLACE_EXISTING;
}
// Only system components can circumvent runtime permissions when installing.
if ((params.installFlags & PackageManager.INSTALL_GRANT_RUNTIME_PERMISSIONS) != 0
&& mContext.checkCallingOrSelfPermission(Manifest.permission
.INSTALL_GRANT_RUNTIME_PERMISSIONS) == PackageManager.PERMISSION_DENIED) {
throw new SecurityException("You need the "
+ "android.permission.INSTALL_GRANT_RUNTIME_PERMISSIONS permission "
+ "to use the PackageManager.INSTALL_GRANT_RUNTIME_PERMISSIONS flag");
}
.......省略
}
得出结论是 mAppOps 为空 。这个玩意是什么请百度,AppOpsManager;
2.这个初始化的地方是在
public void systemReady() {
mAppOps = mContext.getSystemService(AppOpsManager.class);
}
于是加了LOG发现他确实没有走systemReady()方法,所以怎么说这个为空很正常
3.继续跟踪代码发现,他是在PackageManagerService.java中的systemReady()中调用的
@Override
public void systemReady() {
.......
// If we upgraded grant all default permissions before kicking off.
for (int userId : grantPermissionsUserIds) {
mDefaultPermissionPolicy.grantDefaultPermissions(userId);
}
// If we did not grant default permissions, we preload from this the
// default permission exceptions lazily to ensure we don't hit the
// disk on a new user creation.
if (grantPermissionsUserIds == EMPTY_INT_ARRAY) {
mDefaultPermissionPolicy.scheduleReadDefaultPermissionExceptions();
}
// Kick off any messages waiting for system ready
if (mPostSystemReadyMessages != null) {
for (Message msg : mPostSystemReadyMessages) {
msg.sendToTarget();
}
mPostSystemReadyMessages = null;
}
// Watch for external volumes that come and go over time
final StorageManager storage = mContext.getSystemService(StorageManager.class);
storage.registerListener(mStorageListener);
Slog.w("tuliyuan---PKMS"," SYSTEM READY "+(mInstallerService==null));
mInstallerService.systemReady();
mPackageDexOptimizer.systemReady();
..........
很奇怪这里为什么没走,也没有return函数啊,未必pkms的systemReady没走?于是找到启动PKMS的地方SystemServer.java 搜索systemReady
发现
try {
Log.i("tuliyuan---systemserver", "=== mPackageManagerService systemReady ===");
mPackageManagerService.systemReady();
} catch (Throwable e) {
reportWtf("making Package Manager Service ready", e);
}
有个try catch…
心里咯噔一下。不会吧不会吧不会吧? pkms哪里报错了只是崩溃捕获了?
adb reboot;adb logcat -b all > log.txt一看 果然。。。
07-01 17:19:15.925 1113 1113 E SystemServer: BOOT FAILURE making Package Manager Service ready
07-01 17:19:15.925 1113 1113 E SystemServer: java.lang.NullPointerException: Attempt to read from field 'java.util.ArrayList android.content.pm.PackageParser$Package.requestedPermissions' on a null object reference
07-01 17:19:15.925 1113 1113 E SystemServer: at com.android.server.pm.DefaultPermissionGrantPolicy.grantRuntimePermissionsLPw(DefaultPermissionGrantPolicy.java:892)
07-01 17:19:15.925 1113 1113 E SystemServer: at com.android.server.pm.DefaultPermissionGrantPolicy.grantRuntimePermissionsLPw(DefaultPermissionGrantPolicy.java:882)
07-01 17:19:15.925 1113 1113 E SystemServer: at com.android.server.pm.DefaultPermissionGrantPolicy.grantDefaultSystemHandlerPermissions(DefaultPermissionGrantPolicy.java:601)
07-01 17:19:15.925 1113 1113 E SystemServer: at com.android.server.pm.DefaultPermissionGrantPolicy.grantDefaultPermissions(DefaultPermissionGrantPolicy.java:220)
07-01 17:19:15.925 1113 1113 E SystemServer: at com.android.server.pm.PackageManagerService.systemReady(PackageManagerService.java:19041)
07-01 17:19:15.925 1113 1113 E SystemServer: at com.android.server.SystemServer.startOtherServices(SystemServer.java:1553)
07-01 17:19:15.925 1113 1113 E SystemServer: at com.android.server.SystemServer.run(SystemServer.java:420)
07-01 17:19:15.925 1113 1113 E SystemServer: at com.android.server.SystemServer.main(SystemServer.java:292)
07-01 17:19:15.925 1113 1113 E SystemServer: at java.lang.reflect.Method.invoke(Native Method)
07-01 17:19:15.925 1113 1113 E SystemServer: at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1084)
07-01 17:19:15.925 1113 1113 E SystemServer: at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:945)
根据LOG得知是 上面过滤默认权限的时候报错了
然后 找到了该死的错误
PackageParser.Package baidu_location = getSystemPackageLPr("com.baidu.map.location");
grantRuntimePermissionsLPw(baidu_location, STORAGE_PERMISSIONS, userId);
grantRuntimePermissionsLPw(baidu_location, PHONE_PERMISSIONS, userId);
这个baidulocation已经不要了!没有内置,然后找不到包 就错了。。。所以
PackageParser.Package baidu_location = getSystemPackageLPr("com.baidu.map.location");
if(baidu_location != null){
grantRuntimePermissionsLPw(baidu_location, STORAGE_PERMISSIONS, userId);
grantRuntimePermissionsLPw(baidu_location, PHONE_PERMISSIONS, userId);
}
这样就好了
总结
别忘了判断一下空指针异常!!!