int N = pkg.permissions.size();
for (int i = N-1; i >= 0; i–) {
PackageParser.Permission perm = pkg.permissions.get(i);
basePermission bp = mSettings.mPermissions.get(perm.info.name);
if (bp != null) {
// If the defining package is signed with our cert, it’s okay. This
// also includes the “updating the same package” case, of course.
// “updating same package” could also involve key-rotation.
final boolean sigsOk;
if (!bp.sourcePackage.equals(pkg.packageName)
|| !(bp.packageSetting instanceof PackageSetting)
|| !bp.packageSetting.keySetData.isUsingUpgradeKeySets()
|| ((PackageSetting) bp.packageSetting).sharedUser != null) {
sigsOk = compareSignatures(bp.packageSetting.signatures.mSignatures,
pkg.mSignatures) == PackageManager.SIGNATURE_MATCH;
} else {
sigsOk = checkUpgradeKeySetLP((PackageSetting) bp.packageSetting, pkg);
}
if (!sigsOk) {
// If the owning package is the system itself, we log but allow
// install to proceed; we fail the install on all other permission
// redefinitions.
if (!bp.sourcePackage.equals(“android”)) {
res.setError(INSTALL_FAILED_DUPLICATE_PERMISSION, "Package "
pkg.packageName + " attempting to redeclare permission "perm.info.name + " already owned by " + bp.sourcePackage);
res.origPermission = perm.info.name;
res.origPackage = bp.sourcePackage;
return;
} else {
Slog.w(TAG, "Package " + pkg.packageName" attempting to redeclare system permission "perm.info.name + “; ignoring new declaration”);
pkg.permissions.remove(i);
}
}
}
}
// Check if installing already existing package
if ((installFlags & PackageManager.INSTALL_REPLACe_EXISTING) != 0) {
String oldName = mSettings.mRenamedPackages.get(pkgName);
if (pkg.mOriginalPackages != null
&& pkg.mOriginalPackages.contains(oldName)
&& mPackages.containsKey(oldName)) {
// This package is derived from an original package,
// and this device has been updating from that original
// name. We must continue using the original name, so
// rename the new package here.
pkg.setPackageName(oldName);
pkgName = pkg.packageName;
replace = true;
if (DEBUG_INSTALL) Slog.d(TAG, “Replacing existing renamed package: oldName=”
oldName + " pkgName=" + pkgName);
} else if (mPackages.containsKey(pkgName)) {
// This package, under its official name, already exists
// on the device; we should replace it.
replace = true;
if (DEBUG_INSTALL) Slog.d(TAG, "Replace existing pacakge: " + pkgName);
}
}
PackageSetting ps = mSettings.mPackages.get(pkgName);
if (ps != null) {
if (DEBUG_INSTALL) Slog.d(TAG, "Existing package: " + ps);
oldCodePath = mSettings.mPackages.get(pkgName).codePathString;
if (ps.pkg != null && ps.pkg.applicationInfo != null) {
systemApp = (ps.pkg.applicationInfo.flags &
ApplicationInfo.FLAG_SYSTEM) != 0;
}
res.origUsers = ps.queryInstalledUsers(sUserManager.getUserIds(), true);
}
}
if (systemApp && onSd) {
// Disable updates to system apps on sdcard
res.setError(INSTALL_FAILED_INVALID_INSTALL_LOCATION,
“Cannot install updates to system apps on sdcard”);
return;
}
if (!args.doRename(res.returnCode, pkg, oldCodePath)) {
res.setError(INSTALL_FAILED_INSUFFICIENT_STORAGE, “Failed rename”);
return;
}
if (replace) {
replacePackageLI(pkg, parseFlags, scanFlags | SCAN_REPLACING, args.user,
installerPackageName, res);
} else {
installNewPackageLI(pkg, parseFlags, scanFlags | SCAN_DELETE_DATA_ON_FAILURES,
args.user, installerPackageName, res);
}
synchronized (mPackages) {
final PackageSetting ps = mSettings.mPackages.get(pkgName);
if (ps != null) {
res.newUsers = ps.queryInstalledUsers(sUserManager.getUserIds(), true);
}
}
}
这个方法先是解析了package包,然后做了大量签名和权限校验的工作,最终会走到
if (replace) {
replacePackageLI(pkg, parseFlags, scanFlags | SCAN_REPLACING, args.user,
installerPackageName, res);
} else {
installNewPackageLI(pkg, parseFlags, scanFlags | SCAN_DELETE_DATA_ON_FAILURES,
args.user, installerPackageName, res);
}
这两个方法分别是覆盖安装和安装新应用对应的具体执行.我们来看看installNewPackageLI()
2.3 installNewPackageLI()private void installNewPackageLI(PackageParser.Package pkg,
int parseFlags, int scanFlags, UserHandle user,
String installerPackageName, PackageInstalledInfo res) {
// Remember this for later, in case we need to rollback this install
String pkgName = pkg.packageName;
if (DEBUG_INSTALL) Slog.d(TAG, "installNewPackageLI: " + pkg);
boolean dataDirExists = getDataPathForPackage(pkg.packageName, 0).exists();
synchronized(mPackages) {
if (mSettings.mRenamedPackages.containsKey(pkgName)) {
// A package with the same name is already installed, though
// it has been renamed to an older name. The package we
// are trying to install should be installed as an update to
// the existing one, but that has not been requested, so bail.
res.setError(INSTALL_FAILED_ALREADY_EXISTS, "Attempt to re-install " + pkgName
" without first uninstalling package running as "mSettings.mRenamedPackages.get(pkgName));
return;
}
if (mPackages.containsKey(pkgName)) {
// Don’t allow installation over an existing package with the same name.
res.setError(INSTALL_FAILED_ALREADY_EXISTS, "Attempt to re-install " + pkgName" without first uninstalling.");
return;
}
}
try {
PackageParser.Package newPackage = scanPackageLI(pkg, parseFlags, scanFlags,
System.currentTimeMillis(), user);
updateSettingsLI(newPackage, installerPackageName, null, null, res);
// delete the partially installed application. the data directory will have to be
// restored if it was already existing
if (res.returnCode != PackageManager.INSTALL_SUCCEEDED) {
// remove package from internal structures. Note that we want deletePackageX to
// delete the package data and cache directories that it created in
// scanPackageLocked, unless those directories existed before we even tried to
// install.
deletePackageLI(pkgName, UserHandle.ALL, false, null, null,
dataDirExists ? PackageManager.DELETE_KEEP_data: 0,
res.removedInfo, true);
}
} catch (PackageManagerException e) {
res.setError("Package couldn’t be installed in " + pkg.codePath, e);
}
}
这个方法核心的步骤有两个:
PackageParser.Package newPackage = scanPackageLI(pkg, parseFlags, scanFlags,System.currentTimeMillis(), user);updateSettingsLI(newPackage, installerPackageName, null, null, res);
scanPackageLI负责安装,而updateSettingLI则是完成安装后的设置信息更新
2.4 scanPackageLI()scanPackageLI()方法主要逻辑是由scanPackageDirtyLI()实现的,scanPackageDirtyLI()实在太长了,此处就不列出了,主要说下,这个方法实现了以下 *** 作:
设置系统App的一些参数校验签名解析app的provider,校验是否与已有的provider冲突32/64位abi的一些设置四大组件的解析,注册
scanPackageDirtyLI()里面的 *** 作确实是太多了,并不止这几点。如需更详细的信息还请查看源码。
另一方面,这个方法里,会调用到performDexOptLI(),其会去执行dexopt *** 作。
3. dexopt *** 作Apk文件其实只是一个归档zip压缩包,而我们编写的代码最终都编译成了.dex文件,但为了提高运行性能,android系统并不会直接执行.dex,而是会在安装过程中执行dexopt *** 作来优化.dex文件,最终android系统执行的时优化后的’odex’文件(注意:这个odex文件的后缀也是.dex,其路径在data/dalvik-cache)。对于dalvik虚拟机,dexopt就是优化 *** 作,而对于art虚拟机,dexopt执行的则是dex2oat *** 作,既将.dex文件翻译成oat文件。关于art和dex2oat的更多信息请看后文。
这里我们先来看看PMS的dexopt *** 作:
3.1 performDexOptLI()这个方法的核心是
final int ret = mInstaller.dexopt(path, sharedGid, !isForwardLocked(pkg), pkg.packageName, dexCodeInstructionSet, vmSafeMode);
其作用就是调用PMS的mInstaller成员变量的dexopt *** 作。
3.2 Installer.dexoptInstaller类的dexopt方法又调用InstallerConnection类的dexopt方法,来看看这个方法:
public int dexopt(String apkPath, int uid, boolean isPublic, String pkgName,
String instructionSet, boolean vmSafeMode) {
StringBuilder builder = new StringBuilder(“dexopt”);
builder.append(’ ‘);
builder.append(apkPath);
builder.append(’ ‘);
builder.append(uid);
builder.append(isPublic ? " 1" : " 0");
builder.append(’ ‘);
builder.append(pkgName);
builder.append(’ ‘);
builder.append(instructionSet);
builder.append(’ ');
builder.append(vmSafeMode ? " 1" : " 0");
return execute(builder.toString());
}
public synchronized String transact(String cmd) {
if (!connect()) {
Slog.e(TAG, “connection failed”);
return “-1”;
}
if (!writeCommand(cmd)) {
Slog.e(TAG, “write command failed? reconnect!”);
if (!connect() || !writeCommand(cmd)) {
return “-1”;
}
}
if (LOCAL_DEBUG) {
Slog.i(TAG, “send: '” + cmd + “’”);
}
final int replyLength = readReply();
if (replyLength > 0) {
String s = new String(buf, 0, replyLength);
if (LOCAL_DEBUG) {
Slog.i(TAG, “recv: '” + s + “’”);
}
return s;
} else {
if (LOCAL_DEBUG) {
Slog.i(TAG, “fail”);
}
return “-1”;
}
}
public int execute(String cmd) {
String res = transact(cmd);
try {
return Integer.parseInt(res);
} catch (NumberFormatException ex) {
return -1;
}
}
private boolean connect() {
if (mSocket != null) {
return true;
}
Slog.i(TAG, “connecting…”);
try {
mSocket = new LocalSocket();
LocalSocketAddress address = new LocalSocketAddress(“installd”,
LocalSocketAddress.Namespace.RESERVED);
mSocket.connect(address);
mIn = mSocket.getInputStream();
mOut = mSocket.getOutputStream();
} catch (IOException ex) {
disconnect();
return false;
}
return true;
}
由上面的几个方法可以知道,最终dexopt *** 作是通过socket的方式来跨进程通知守护进程installd,由其去执行dexopt *** 作。
3.3 commands::dexopt()最终守护进程installd会调用Commands.c文件(位于/source/framework/native/cmds/installd)的dexopt方法。
int dexopt(const char *apk_path, uid_t uid, bool is_public,
const char *pkgname, const char *instruction_set,
bool vm_safe_mode, bool is_patchoat)
{
struct utimbuf ut;
struct stat input_stat, dex_stat;
char out_path[PKG_PATH_MAX];
char persist_sys_dalvik_vm_lib[PROPERTY_VALUE_MAX];
char *end;
const char *input_file;
char in_odex_path[PKG_PATH_MAX];
int res, input_fd=-1, out_fd=-1;
…
…
pid_t pid;
pid = fork();
if (pid == 0) {
if (setgid(uid) != 0) {
ALOGE(“setgid(%d) failed in installd during dexoptn”, uid);
exit(64);
}
if (setuid(uid) != 0) {
ALOGE(“setuid(%d) failed in installd during dexoptn”, uid);
exit(65);
}
// drop capabilities
struct __user_cap_header_struct capheader;
struct __user_cap_data_struct capdata[2];
memset(&capheader, 0, sizeof(capheader));
memset(&capdata, 0, sizeof(capdata));
capheader.version = _LINUX_CAPABILITY_VERSION_3;
if (capset(&capheader, &capdata[0]) < 0) {
ALOGE(“capset failed: %sn”, strerror(errno));
exit(66);
}
if (set_sched_policy(0, SP_BACKGROUND) < 0) {
ALOGE(“set_sched_policy failed: %sn”, strerror(errno));
exit(70);
}
if (flock(out_fd, LOCK_EX | LOCK_NB) != 0) {
ALOGE(“flock(%s) failed: %sn”, out_path, strerror(errno));
exit(67);
}
if (strncmp(persist_sys_dalvik_vm_lib, “libdvm”, 6) == 0) {
run_dexopt(input_fd, out_fd, input_file, out_path);
} else if (strncmp(persist_sys_dalvik_vm_lib, “libart”, 6) == 0) {
if (is_patchoat) {
run_patchoat(input_fd, out_fd, input_file, out_path, pkgname, instruction_set);
} else {
run_dex2oat(input_fd, out_fd, input_file, out_path, pkgname, instruction_set,
vm_safe_mode);
}
} else {
exit(69);
} else {
res = wait_child(pid);
if (res == 0) {
ALOGV(“DexInv: — END ‘%s’ (success) —n”, input_file);
} else {
ALOGE(“DexInv: — END ‘%s’ — status=0x%04x, process failedn”, input_file, res);
goto fail;
}
}
ut.actime = input_stat.st_atime;
ut.modtime = input_stat.st_mtime;
utime(out_path, &ut);
close(out_fd);
close(input_fd);
return 0;
fail:
if (out_fd >= 0) {
close(out_fd);
unlink(out_path);
}
if (input_fd >= 0) {
close(input_fd);
}
return -1;
}
由上面的代码可以发现,installd在做了些 *** 作后,fork出了一个新的进程,根据虚拟机的类型为libdvm或libart分别执行run_dexopt或run_dex2oat(如果为is_patchoat,则是run_patchoat) *** 作。
4. 更新权限信息dexopt *** 作执行完后,installNewPackageLI()方法就会走到updateSettingsLI()来更新设置信息,而更新设置信息主要是权限信息,所以直接来看updatePermissionsLPw();
4.1 updatePermissionsLPwprivate void updatePermissionsLPw(String changingPkg,
PackageParser.Package pkgInfo, int flags) {
// Make sure there are no dangling permission trees.
Iterator it = mSettings.mPermissionTrees.values().iterator();
while (it.hasNext()) {
final basePermission bp = it.next();
if (bp.packageSetting == null) {
// We may not yet have parsed the package, so just see if
// we still know about its settings.
bp.packageSetting = mSettings.mPackages.get(bp.sourcePackage);
}
if (bp.packageSetting == null) {
Slog.w(TAG, "Removing dangling permission tree: " + bp.name
" from package " + bp.sourcePackage);
it.remove();
} else if (changingPkg != null && changingPkg.equals(bp.sourcePackage)) {
if (pkgInfo == null || !hasPermission(pkgInfo, bp.name)) {
Slog.i(TAG, "Removing old permission tree: " + bp.name" from package " + bp.sourcePackage);
flags |= UPDATe_PERMISSIONS_ALL;
it.remove();
}
}
}
// Make sure all dynamic permissions have been assigned to a package,
// and make sure there are no dangling permissions.
it = mSettings.mPermissions.values().iterator();
while (it.hasNext()) {
final basePermission bp = it.next();
if (bp.type == basePermission.TYPE_DYNAMIC) {
if (DEBUG_SETTINGS) Log.v(TAG, “Dynamic permission: name=”
bp.name + " pkg=" + bp.sourcePackage" info=" + bp.pendingInfo);
if (bp.packageSetting == null && bp.pendingInfo != null) {
final basePermission tree = findPermissionTreeLP(bp.name);
if (tree != null && tree.perm != null) {
bp.packageSetting = tree.packageSetting;
bp.perm = new PackageParser.Permission(tree.perm.owner,
new PermissionInfo(bp.pendingInfo));
bp.perm.info.packageName = tree.perm.info.packageName;
bp.perm.info.name = bp.name;
bp.uid = tree.uid;
}
}
}
if (bp.packageSetting == null) {
// We may not yet have parsed the package, so just see if
// we still know about its settings.
bp.packageSetting = mSettings.mPackages.get(bp.sourcePackage);
}
if (bp.packageSetting == null) {
Slog.w(TAG, "Removing dangling permission: " + bp.name" from package " + bp.sourcePackage);
it.remove();
} else if (changingPkg != null && changingPkg.equals(bp.sourcePackage)) {
if (pkgInfo == null || !hasPermission(pkgInfo, bp.name)) {
Slog.i(TAG, "Removing old permission: " + bp.name" from package " + bp.sourcePackage);
flags |= UPDATE_PERMISSIONS_ALL;
it.remove();
}
}
}
// Now update the permissions for all packages, in particular
// replace the granted permissions of the system packages.
if ((flags&UPDATE_PERMISSIONS_ALL) != 0) {
for (PackageParser.Package pkg : mPackages.values()) {
if (pkg != pkgInfo) {
grantPermissionsLPw(pkg, (flags&UPDATE_PERMISSIONS_REPLACE_ALL) != 0,
changingPkg);
}
}
}
if (pkgInfo != null) {
grantPermissionsLPw(pkgInfo, (flags&UPDATE_PERMISSIONS_REPLACE_PKG) != 0, changingPkg);
}
}
private void grantPermissionsLPw(PackageParser.Package pkg, boolean replace,
String packageOfInterest) {
final PackageSetting ps = (PackageSetting) pkg.mExtras;
if (ps == null) {
return;
}
final GrantedPermissions gp = ps.sharedUser != null ? ps.sharedUser : ps;
HashSet origPermissions = gp.grantedPermissions;
boolean changedPermission = false;
if (replace) {
ps.permissionsFixed = false;
if (gp == ps) {
origPermissions = new HashSet(gp.grantedPermissions);
gp.grantedPermissions.clear();
gp.gids = mGlobalGids;
}
}
if (gp.gids == null) {
gp.gids = mGlobalGids;
}
final int N = pkg.requestedPermissions.size();
for (int i=0; i
final boolean required = pkg.requestedPermissionsRequired.get(i);
final basePermission bp = mSettings.mPermissions.get(name);
if (DEBUG_INSTALL) {
if (gp != ps) {
Log.i(TAG, "Package " + pkg.packageName + " checking " + name + ": " + bp);
}
}
if (bp == null || bp.packageSetting == null) {
if (packageOfInterest == null || packageOfInterest.equals(pkg.packageName)) {
Slog.w(TAG, "Unknown permission " + name
" in package " + pkg.packageName);
}
文末
初级工程师拿到需求会直接开始做,然后做着做着发现有问题了,要么技术实现不了,要么逻辑有问题。
而高级工程师拿到需求会考虑很多,技术的可行性?对现有业务有没有帮助?对现有技术架构的影响?扩展性如何?等等…之后才会再进行设计编码阶段。
而现在随着跨平台开发,混合式开发,前端开发之类的热门,Android开发者需要学习和掌握的技术也在不断的增加。
通过和一些行业里的朋友交流讨论,以及参考现在大厂面试的要求。我们花了差不多一个月时间整理出了这份Android高级工程师需要掌握的所有知识体系。你可以看下掌握了多少。
混合式开发,微信小程序。都是得学会并且熟练的
这些是Android相关技术的内核,还有Java进阶
高级进阶必备的一些技术。像移动开发架构项目实战等
Android前沿技术;包括了组件化,热升级和热修复,以及各种架构跟框架的详细技术体系
以上即是我们整理的Android高级工程师需要掌握的技术体系了。可能很多朋友觉得很多技术自己都会了,只是一些新的技术不清楚而已。应该没什么太大的问题。
而这恰恰是问题所在!为什么别人高级工程师能年限突破30万,而你只有十几万呢?
就因为你只需补充你自己认为需要的,但并不知道企业需要的。这个就特别容易造成差距。因为你的技术体系并不系统,是零碎的,散乱的。那么你凭什么突破30万年薪呢?
我这些话比较直接,可能会戳到一些人的玻璃心,但是我知道肯定会对一些人起到点醒的效果的。而但凡只要有人因为我的这份高级系统大纲以及这些话找到了方向,并且付出行动去提升自我,为了成功变得更加努力。那么我做的这些就都有了意义。
喜欢的话请帮忙转发点赞一下能让更多有需要的人看到吧。谢谢!以上系统大纲里包含的所有技术资料,我这里都有的。可以免费分享给有需要的朋友!
高级进阶必备的一些技术。像移动开发架构项目实战等
[外链图片转存中…(img-6HMmxI2t-1643964015847)]
Android前沿技术;包括了组件化,热升级和热修复,以及各种架构跟框架的详细技术体系
[外链图片转存中…(img-sDxxZeQ3-1643964015848)]
以上即是我们整理的Android高级工程师需要掌握的技术体系了。可能很多朋友觉得很多技术自己都会了,只是一些新的技术不清楚而已。应该没什么太大的问题。
而这恰恰是问题所在!为什么别人高级工程师能年限突破30万,而你只有十几万呢?
就因为你只需补充你自己认为需要的,但并不知道企业需要的。这个就特别容易造成差距。因为你的技术体系并不系统,是零碎的,散乱的。那么你凭什么突破30万年薪呢?
我这些话比较直接,可能会戳到一些人的玻璃心,但是我知道肯定会对一些人起到点醒的效果的。而但凡只要有人因为我的这份高级系统大纲以及这些话找到了方向,并且付出行动去提升自我,为了成功变得更加努力。那么我做的这些就都有了意义。
喜欢的话请帮忙转发点赞一下能让更多有需要的人看到吧。谢谢!以上系统大纲里包含的所有技术资料,我这里都有的。可以免费分享给有需要的朋友!
资料领取方式:点击我的GitHub
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)