如何成为Android高级架构师!

架构师必须具备抽象思维和分析的能力,这是你进行系统分析和系统分解的基本素质。只有具备这样的能力,架构师才能看清系统的整体,掌控全局,这也是架构师大局观的形成基础。 你如何具备这种能力呢?一是来自于经验,二是来自于学习。

架构师不仅要具备在问题领域上的经验,也需要具备在软件工程领域内的经验。也就是说,架构师必须能够准确得理解需求,然后用软件工程的思想,把需求转化和分解成可用计算机语言实现的程度。经验的积累是需要一个时间过程的,这个过程谁也帮不了你,是需要你去经历的。

但是,如果你有意识地去培养,不断吸取前人的经验的话,还是可以缩短这个周期的。这也是我整理架构师进阶此系列的始动力之一。

成为Android架构师必备知识技能

对应导图的学习笔记(由阿里P8大牛手写,我负责整理成PDF笔记)

部分内容展示

《设计思想解读开源框架》

目录 热修复设计 插件化框架设计 《360°全方面性能优化》 设计思想与代码质量优化 程序性能优化

网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。

需要这份系统化学习资料的朋友,可以戳这里获取

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

public int noteOp(Context context, String op, int uid, String packageName) { return MODE_IGNORED; }

public int noteProxyOp(Context context, String op, String proxiedPackageName) { return MODE_IGNORED; } }

private static class AppOpsManager23 extends AppOpsManagerImpl { @Override public String permissionToOp(String permission) { return AppOpsManagerCompat23.permissionToOp(permission); }

@Override public int noteOp(Context context, String op, int uid, String packageName) { return AppOpsManagerCompat23.noteOp(context, op, uid, packageName); }

@Override public int noteProxyOp(Context context, String op, String proxiedPackageName) { return AppOpsManagerCompat23.noteProxyOp(context, op, proxiedPackageName); } }

上面的是6.0之前对应的API,下面的是6.0及其之后对应的接口,AppOpsManagerCompat23.noteProxyOp会进一步调用AppOpsManager的noteProxyOp向AppOpsService发送请求

public static int noteProxyOp(Context context, String op, String proxiedPackageName) { AppOpsManager appOpsManager = context.getSystemService(AppOpsManager.class); return appOpsManager.noteProxyOp(op, proxiedPackageName); }

最后看一下AppOpsService如何检查权限

private int noteOperationUnchecked(int code, int uid, String packageName, int proxyUid, String proxyPackageName) { synchronized (this) { Ops ops = getOpsLocked(uid, packageName, true); Op op = getOpLocked(ops, code, true); if (isOpRestricted(uid, code, packageName)) { return AppOpsManager.MODE_IGNORED; } op.duration = 0; final int switchCode = AppOpsManager.opToSwitch(code); UidState uidState = ops.uidState; if (uidState.opModes != null) { final int uidMode = uidState.opModes.get(switchCode); op.rejectTime = System.currentTimeMillis(); return uidMode; } } final Op switchOp = switchCode != code ? getOpLocked(ops, switchCode, true) : op; if (switchOp.mode != AppOpsManager.MODE_ALLOWED) { op.rejectTime = System.currentTimeMillis(); return switchOp.mode; } op.time = System.currentTimeMillis(); op.rejectTime = 0; op.proxyUid = proxyUid; op.proxyPackageName = proxyPackageName; return AppOpsManager.MODE_ALLOWED; } }

UidState可以看做每个应用对应的权限模型,这里的数据是有一部分是从appops.xml恢复回来,也有部分是在更新权限时候加进去的,这部分变化最终都要持久化到appops.xml中去,不过持久化比较滞后,一般要等到手机更新权限后30分钟才会持久化到appops.xml中,这里的数据一般是在启动的时候被恢复重建,在启动ActivityManagerService服务的时候,会在其构造函数总启动AppOpsService服务:

public ActivityManagerService(Context systemContext) { … mAppOpsService = new AppOpsService(new File(systemDir, “appops.xml”), mHandler); …}

在AppOpsService的构造函数中会将持久化到appops.xml中的权限信息恢复出来,并存到内存中去,

public AppOpsService(File storagePath, Handler handler) { mFile = new AtomicFile(storagePath); mHandler = handler; // 新建的时候就会读取 readState(); }

readState就是将持久化的UidState数据给重新读取出来,如下mFile其实就是appops.xml的文件对象

void readState() { synchronized (mFile) { synchronized (this) { FileInputStream stream; try { stream = mFile.openRead(); } catch (FileNotFoundException e) { } boolean success = false; mUidStates.clear(); try { XmlPullParser parser = Xml.newPullParser(); parser.setInput(stream, StandardCharsets.UTF_8.name()); int type; int outerDepth = parser.getDepth(); while ((type = parser.next()) != XmlPullParser.END_DOCUMENT && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) { if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) { continue; } String tagName = parser.getName(); if (tagName.equals(“pkg”)) { readPackage(parser); } else if (tagName.equals(“uid”)) { readUidOps(parser); } else { XmlUtils.skipCurrentTag(parser); } } success = true; …}

读取之后,当用户操作权限的时候,也会随机的更新这里的标记,只看下targetSdkVersion<23的,

public boolean grantRuntimePermissions(boolean fixedByTheUser, String[] filterPermissions) { final int uid = mPackageInfo.applicationInfo.uid;

for (Permission permission : mPermissions.values()) { if (filterPermissions != null && !ArrayUtils.contains(filterPermissions, permission.getName())) { continue; }

if (mAppSupportsRuntimePermissions) { … } else { if (!permission.isGranted()) { continue; } int killUid = -1; int mask = 0; if (permission.hasAppOp()) { if (!permission.isAppOpAllowed()) { permission.setAppOpAllowed(true);

mAppOps.setUidMode(permission.getAppOp(), uid, AppOpsManager.MODE_ALLOWED); killUid = uid; } } if (mask != 0) { mPackageManager.updatePermissionFlags(permission.getName(), mPackageInfo.packageName, mask, 0, mUserHandle); } } } return true; }

拿授权的场景来说,其实关键就是 mAppOps.setUidMode(permission.getAppOp(), uid, AppOpsManager.MODE_ALLOWED)函数,这个函数会更新AppOpsService中对于权限的标记,并将权限是否授予的信息持久化到appops.xml及packages.xml,不同版本可能有差别,有可能需要appops.xml跟packages.xml配合才能确定是否授予权限,具体没深究,有兴趣可以自行分析。

@Override public void setUidMode(int code, int uid, int mode) { if (Binder.getCallingPid() != Process.myPid()) { mContext.enforcePermission(android.Manifest.permission.UPDATE_APP_OPS_STATS, Binder.getCallingPid(), Binder.getCallingUid(), null); } verifyIncomingOp(code); code = AppOpsManager.opToSwitch(code);

synchronized (this) { final int defaultMode = AppOpsManager.opToDefaultMode(code);

UidState uidState = getUidStateLocked(uid, false); if (uidState == null) { if (mode == defaultMode) { return; } uidState = new UidState(uid); uidState.opModes = new SparseIntArray(); uidState.opModes.put(code, mode); mUidStates.put(uid, uidState); scheduleWriteLocked(); } else if (uidState.opModes == null) { if (mode != defaultMode) { uidState.opModes = new SparseIntArray(); uidState.opModes.put(code, mode); scheduleWriteLocked(); } } else { if (uidState.opModes.get(code) == mode) { return; } if (mode == defaultMode) { uidState.opModes.delete(code); if (uidState.opModes.size() <= 0) { uidState.opModes = null; } } else { uidState.opModes.put(code, mode); }

scheduleWriteLocked(); } } … }

这里有一点注意:scheduleWriteLocked并不是立即执行写操作,而是比更新内存滞后,一般滞后30分钟

static final long WRITE_DELAY = DEBUG ? 1000 : 30601000;

30分钟才会去更新 ,不过内存中都是最新的 ,如果直接删除appops.xml,然后意外重启,比如adb reboot bootloader,那么你的所有AppOpsService权限标记将会被清空,经过验证,是符合预期的,也就说,targetSdkVersion<23的情况下,Android6.0以上的手机,它的权限操作是持久化在appops.xml中的,一般关机的时候,会持久化一次,如果还没来得及持久化,异常关机,就会丢失,这点同runtime-permission类似,异常关机也会丢失,不信可以试验一下 。

在targetSdkVersion>=23的时候,对于 SDK>=23的机器如何检测权限

targetSdkVersion>=23系统已经提供了比较合理的检测手段,PermisionChecker的checkPermission就可以,不过,这里需要注意的是,AppOpsService对于targetSdkVersion>=23的时候就不能用了,这里可能是Android的一个bug,当targetSdkVersion>=23而SDK_Version>=23的,对于AppOpsService,权限的授予跟撤销不是配对的,如下,先简单看下授权:

public boolean grantRuntimePermissions(boolean fixedByTheUser, String[] filterPermissions) { final int uid = mPackageInfo.applicationInfo.uid;

for (Permission permission : mPermissions.values()) {

if (mAppSupportsRuntimePermissions) {

if (permission.hasAppOp() && !permission.isAppOpAllowed()) { permission.setAppOpAllowed(true); mAppOps.setUidMode(permission.getAppOp(), uid, AppOpsManager.MODE_ALLOWED); } if (!permission.isGranted()) { permission.setGranted(true); mPackageManager.grantRuntimePermission(mPackageInfo.packageName, permission.getName(), mUserHandle); } } else { if (!permission.isGranted()) { continue; }

int killUid = -1; int mask = 0;

if (permission.hasAppOp()) { if (!permission.isAppOpAllowed()) { permission.setAppOpAllowed(true); // Enable the app op. mAppOps.setUidMode(permission.getAppOp(), uid, AppOpsManager.MODE_ALLOWED); killUid = uid; } … } }

return true; }

可见,对于6.0的系统,无论targetSdkVersion是否>=23,在授权的时候,都会更新appops.xml,那取消授权呢?

public boolean revokeRuntimePermissions(boolean fixedByTheUser, String[] filterPermissions) { final int uid = mPackageInfo.applicationInfo.uid; for (Permission permission : mPermissions.values()) { … if (mAppSupportsRuntimePermissions) { if (permission.isSystemFixed()) { return false; }

// Revoke the permission if needed. if (permission.isGranted()) { permission.setGranted(false); mPackageManager.revokeRuntimePermission(mPackageInfo.packageName, permission.getName(), mUserHandle); }

总结

其实要轻松掌握很简单,要点就两个:

找到一套好的视频资料,紧跟大牛梳理好的知识框架进行学习。多练。 (视频优势是互动感强,容易集中注意力)

你不需要是天才,也不需要具备强悍的天赋,只要做到这两点,短期内成功的概率是非常高的。

对于很多初中级Android工程师而言,想要提升技能,往往是自己摸索成长,不成体系的学习效果低效漫长且无助。下面资料部分截图是我花费几个月时间整理的,诚意满满:特别适合有3-5年开发经验的Android程序员们学习。

网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。

需要这份系统化学习资料的朋友,可以戳这里获取

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

对于很多初中级Android工程师而言,想要提升技能,往往是自己摸索成长,不成体系的学习效果低效漫长且无助。下面资料部分截图是我花费几个月时间整理的,诚意满满:特别适合有3-5年开发经验的Android程序员们学习。

[外链图片转存中…(img-qZOuVT3L-1715712774107)]

网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。

需要这份系统化学习资料的朋友,可以戳这里获取

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

推荐链接

评论可见,请评论后查看内容,谢谢!!!评论后请刷新页面。