如何成为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行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!