您的位置:首页 > 移动开发 > Android开发

Android应用安装过程分析(一)

2016-07-21 00:33 387 查看
手头上只有Android4.3的源代码,凑活着看,过程都大差不差,哪里写的不对的希望看到的大神指出。

Android应用安全有四种方式:

1.通过SD卡里的APK文件安装
2.网络下载应用安装,通过market应用完成,没有安装界面
3.ADB工具安装,没有安装界面。
4.系统应用安装,开机时完成。
先看SD卡中APK文件安装
一般通过java代码进行应用安装会创建Intent对象,调用startActivity安装指定APK
Intent intent = new Intent(Intent.ACTION_INSTALL_PACKAGE);
intent.setData(Uri.parse("file:/sdcard/xxx.apk"));
startActivity(intent);之后会进入校验页面PackageInstallerActivity
源码路径:android/packages/apps/PackageInstaller/src/com/android/packageinstaller/PackageInstallerActivity.java

public class PackageInstallerActivity extends Activity implements OnCancelListener, OnClickListener {
private static final String TAG = "PackageInstaller";
private Uri mPackageURI;
private Uri mOriginatingURI;
private Uri mReferrerURI;
private int mOriginatingUid = VerificationParams.NO_UID;
private ManifestDigest mPkgDigest;

private boolean localLOGV = false;
PackageManager mPm;
PackageInfo mPkgInfo;
ApplicationInfo mSourceInfo;

// ApplicationInfo object primarily used for already existing applications
private ApplicationInfo mAppInfo = null;

// View for install progress
View mInstallConfirm;
// Buttons to indicate user acceptance
private Button mOk;
private Button mCancel;
CaffeinatedScrollView mScrollView = null;
private boolean mOkCanInstall = false;

static final String PREFS_ALLOWED_SOURCES = "allowed_sources";

// Dialog identifiers used in showDialog
private static final int DLG_BASE = 0;
private static final int DLG_UNKNOWN_APPS = DLG_BASE + 1;
private static final int DLG_PACKAGE_ERROR = DLG_BASE + 2;
private static final int DLG_OUT_OF_SPACE = DLG_BASE + 3;
private static final int DLG_INSTALL_ERROR = DLG_BASE + 4;
private static final int DLG_ALLOW_SOURCE = DLG_BASE + 5;
@Override
protected void onCreate(Bundle icicle) {
super.onCreate(icicle);

// get intent information
final Intent intent = getIntent();
mPackageURI = intent.getData();<span style="white-space:pre">		</span>//获取应用路径或Package
mOriginatingURI = intent.getParcelableExtra(Intent.EXTRA_ORIGINATING_URI);
mReferrerURI = intent.getParcelableExtra(Intent.EXTRA_REFERRER);
mPm = getPackageManager();<span style="white-space:pre">		</span>//创建PackageManager对象

final String scheme = mPackageURI.getScheme();<span style="white-space:pre">					</span>//返回当前协议
if (scheme != null && !"file".equals(scheme) && !"package".equals(scheme)) {<span style="white-space:pre">	</span>//协议类型判断
Log.w(TAG, "Unsupported scheme " + scheme);
setPmResult(PackageManager.INSTALL_FAILED_INVALID_URI);<span style="white-space:pre">			</span>//设置返回结果信息
return;
}

final PackageUtil.AppSnippet as;
if ("package".equals(mPackageURI.getScheme())) {<span style="white-space:pre">						</span>//协议类型为package
try {
mPkgInfo = mPm.getPackageInfo(mPackageURI.getSchemeSpecificPart(),
PackageManager.GET_PERMISSIONS | PackageManager.GET_UNINSTALLED_PACKAGES);<span style="white-space:pre">	</span>//获取应用信息,如应用名、权限等
} catch (NameNotFoundException e) {
}
if (mPkgInfo == null) {<span style="white-space:pre">		</span>//获取失败处理分支
Log.w(TAG, "Requested package " + mPackageURI.getScheme()
+ " not available. Discontinuing installation");
showDialogInner(DLG_PACKAGE_ERROR);
setPmResult(PackageManager.INSTALL_FAILED_INVALID_APK);
return;
}
as = new PackageUtil.AppSnippet(mPm.getApplicationLabel(mPkgInfo.applicationInfo),<span style="white-space:pre">	</span>//AppSnippet对象封装了应用的标题和图标
mPm.getApplicationIcon(mPkgInfo.applicationInfo));
} else {<span style="white-space:pre">										</span>//协议类型为file
final File sourceFile = new File(mPackageURI.getPath());<span style="white-space:pre">				</span>//根据路径创建文件对象
PackageParser.Package parsed = PackageUtil.getPackageInfo(sourceFile);<span style="white-space:pre">		</span>//创建文件分析器

// Check for parse errors
if (parsed == null) {
Log.w(TAG, "Parse error when parsing manifest. Discontinuing installation");
showDialogInner(DLG_PACKAGE_ERROR);
setPmResult(PackageManager.INSTALL_FAILED_INVALID_APK);
return;
}
mPkgInfo = PackageParser.generatePackageInfo(parsed, null,
PackageManager.GET_PERMISSIONS, 0, 0, null,
new PackageUserState());<span style="white-space:pre">				</span>//获取应用信息
mPkgDigest = parsed.manifestDigest;
as = PackageUtil.getAppSnippet(this, mPkgInfo.applicationInfo, sourceFile);
}

//set view
setContentView(R.layout.install_start);<span style="white-space:pre">				</span>//设置画面
mInstallConfirm = findViewById(R.id.install_confirm_panel);
mInstallConfirm.setVisibility(View.INVISIBLE);
PackageUtil.initSnippetForNewApp(this, as, R.id.app_snippet);

mOriginatingUid = getOriginatingUid(intent);

// Deal with install source.
String callerPackage = getCallingPackage();//<span style="color: rgb(51, 51, 51); font-family: Roboto, sans-serif; font-size: 14px; line-height: 24px;">Return the name of the package that invoked this activity</span>
if (callerPackage != null && intent.getBooleanExtra(
Intent.EXTRA_NOT_UNKNOWN_SOURCE, false)) {
try {
mSourceInfo = mPm.getApplicationInfo(callerPackage, 0);
if (mSourceInfo != null) {
if ((mSourceInfo.flags&ApplicationInfo.FLAG_SYSTEM) != 0) {
// System apps don't need to be approved.
initiateInstall();
return;
}
}
} catch (NameNotFoundException e) {
}
}

// Check unknown sources.判断是否允许未知来源的应用
if (!isInstallingUnknownAppsAllowed()) {
//ask user to enable setting first询问是否要通过设置打开未知来源
showDialogInner(DLG_UNKNOWN_APPS);
return;
}
initiateInstall();
}
检查协议,根据不同协议进行处理,最终都会调用initiateInstall

private void initiateInstall() {
String pkgName = mPkgInfo.packageName;<span style="white-space:pre">						</span>
// Check if there is already a package on the device with this name
// but it has been renamed to something else.
String[] oldName = mPm.canonicalToCurrentPackageNames(new String[] { pkgName });
if (oldName != null && oldName.length > 0 && oldName[0] != null) {
pkgName = oldName[0];
mPkgInfo.packageName = pkgName;
mPkgInfo.applicationInfo.packageName = pkgName;
}
// Check if package is already installed. display confirmation dialog if replacing pkg
try {
// This is a little convoluted because we want to get all uninstalled
// apps, but this may include apps with just data, and if it is just
// data we still want to count it as "installed".
mAppInfo = mPm.getApplicationInfo(pkgName,
PackageManager.GET_UNINSTALLED_PACKAGES);
if ((mAppInfo.flags&ApplicationInfo.FLAG_INSTALLED) == 0) {
mAppInfo = null;
}
} catch (NameNotFoundException e) {
mAppInfo = null;
}
startInstallConfirm();//开始安装认证
}

initiateInstall就是进行检查,是否已存在,检查完毕调用startInstallConfirm

private void startInstallConfirm() {
TabHost tabHost = (TabHost)findViewById(android.R.id.tabhost);
tabHost.setup();
ViewPager viewPager = (ViewPager)findViewById(R.id.pager);
TabsAdapter adapter = new TabsAdapter(this, tabHost, viewPager);

boolean permVisible = false;<span style="white-space:pre"> </span>//是否显示权限,true显示,false不显示
mScrollView = null;
mOkCanInstall = false;
int msg = 0;
if (mPkgInfo != null) {
AppSecurityPermissions perms = new AppSecurityPermissions(this, mPkgInfo);<span style="white-space:pre"> </span>//AppSecurityPermissions封装了一些处理权限的<span style="white-space:pre"> </span>//功能
final int NP = perms.getPermissionCount(AppSecurityPermissions.WHICH_PERSONAL);//隐私权限数量
final int ND = perms.getPermissionCount(AppSecurityPermissions.WHICH_DEVICE); //设备权限数量
if (mAppInfo != null) {
msg = (mAppInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0 //判断是否为系统应用设置msg,该值用于确定不同的布局文件
? R.string.install_confirm_question_update_system
: R.string.install_confirm_question_update;
mScrollView = new CaffeinatedScrollView(this);<span style="white-space:pre"> </span>//用于显示权限的滚动视图
mScrollView.setFillViewport(true);
if (perms.getPermissionCount(AppSecurityPermissions.WHICH_NEW) > 0) { //判断应用有新权限
permVisible = true;
mScrollView.addView(perms.getPermissionsView(<span style="white-space:pre"> </span>//将权限加入滚动视图
AppSecurityPermissions.WHICH_NEW));
} else {<span style="white-space:pre"> </span>//没有需要显示的权限,只显示名称和图标
LayoutInflater inflater = (LayoutInflater)getSystemService(
Context.LAYOUT_INFLATER_SERVICE);
TextView label = (TextView)inflater.inflate(R.layout.label, null);
label.setText(R.string.no_new_perms);
mScrollView.addView(label);
}
adapter.addTab(tabHost.newTabSpec("new").setIndicator(
getText(R.string.newPerms)), mScrollView);
} else {
findViewById(R.id.tabscontainer).setVisibility(View.GONE);
findViewById(R.id.divider).setVisibility(View.VISIBLE);
}
if (NP > 0 || ND > 0) {
permVisible = true;
LayoutInflater inflater = (LayoutInflater)getSystemService(
Context.LAYOUT_INFLATER_SERVICE);
View root = inflater.inflate(R.layout.permissions_list, null);
if (mScrollView == null) {
mScrollView = (CaffeinatedScrollView)root.findViewById(R.id.scrollview);
}
if (NP > 0) {<span style="white-space:pre"> </span>//滚动视图显示与隐私相关
((ViewGroup)root.findViewById(R.id.privacylist)).addView(
perms.getPermissionsView(AppSecurityPermissions.WHICH_PERSONAL));
} else {
root.findViewById(R.id.privacylist).setVisibility(View.GONE);
}
if (ND > 0) {<span style="white-space:pre"> </span>//显示与设备相关
((ViewGroup)root.findViewById(R.id.devicelist)).addView(
perms.getPermissionsView(AppSecurityPermissions.WHICH_DEVICE));
} else {
root.findViewById(R.id.devicelist).setVisibility(View.GONE);
}
adapter.addTab(tabHost.newTabSpec("all").setIndicator(
getText(R.string.allPerms)), root);
}
}
if (!permVisible) {<span style="white-space:pre"> </span>//没有任何权限
if (mAppInfo != null) {
// This is an update to an application, but there are no
// permissions at all.
msg = (mAppInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0
? R.string.install_confirm_question_update_system_no_perms
: R.string.install_confirm_question_update_no_perms;
} else {
// This is a new application with no permissions.
msg = R.string.install_confirm_question_no_perms;
}
tabHost.setVisibility(View.GONE);
findViewById(R.id.filler).setVisibility(View.VISIBLE);
findViewById(R.id.divider).setVisibility(View.GONE);
mScrollView = null;
}
if (msg != 0) {<span style="white-space:pre"> </span>//选择布局文件
((TextView)findViewById(R.id.install_confirm_question)).setText(msg);
}
mInstallConfirm.setVisibility(View.VISIBLE);
mOk = (Button)findViewById(R.id.ok_button);
mCancel = (Button)findViewById(R.id.cancel_button);
mOk.setOnClickListener(this);
mCancel.setOnClickListener(this);
if (mScrollView == null) {
// There is nothing to scroll view, so the ok button is immediately
// set to install.
mOk.setText(R.string.install);
mOkCanInstall = true;
} else {
mScrollView.setFullScrollAction(new Runnable() {
@Override
public void run() {
mOk.setText(R.string.install);
mOkCanInstall = true;
}
});
}
}正常情况下,此时单击按钮“安装”,即安装应用
public void onClick(View v) {
if(v == mOk) {
if (mOkCanInstall || mScrollView == null) {<span style="white-space:pre"> </span>//选择“安装”按钮
// Start subactivity to actually install the application
Intent newIntent = new Intent();
newIntent.putExtra(PackageUtil.INTENT_ATTR_APPLICATION_INFO,
mPkgInfo.applicationInfo);
newIntent.setData(mPackageURI);
newIntent.setClass(this, InstallAppProgress.class);
newIntent.putExtra(InstallAppProgress.EXTRA_MANIFEST_DIGEST, mPkgDigest);
String installerPackageName = getIntent().getStringExtra(
Intent.EXTRA_INSTALLER_PACKAGE_NAME);
if (mOriginatingURI != null) {
newIntent.putExtra(Intent.EXTRA_ORIGINATING_URI, mOriginatingURI);
}
if (mReferrerURI != null) {
newIntent.putExtra(Intent.EXTRA_REFERRER, mReferrerURI);
}
if (mOriginatingUid != VerificationParams.NO_UID) {
newIntent.putExtra(Intent.EXTRA_ORIGINATING_UID, mOriginatingUid);
}
if (installerPackageName != null) {
newIntent.putExtra(Intent.EXTRA_INSTALLER_PACKAGE_NAME,
installerPackageName);
}
if (getIntent().getBooleanExtra(Intent.EXTRA_RETURN_RESULT, false)) {
newIntent.putExtra(Intent.EXTRA_RETURN_RESULT, true);
newIntent.addFlags(Intent.FLAG_ACTIVITY_FORWARD_RESULT);
}
if(localLOGV) Log.i(TAG, "downloaded app uri="+mPackageURI);
startActivity(newIntent);<span style="white-space:pre"> </span>//开始安装界面
finish();
} else {<span style="white-space:pre"> </span>//单击“下一步”按钮继续显示权限列表
mScrollView.pageScroll(View.FOCUS_DOWN);
}
} else if(v == mCancel) {
// Cancel and finish
setResult(RESULT_CANCELED);
finish();
}
}
}启动安装界面就会进入InstallAppProgress,与PackageInstallerActivity在同一个包下
@Override
public void onCreate(Bundle icicle) {
super.onCreate(icicle);
Intent intent = getIntent();<span style="white-space:pre"> </span>//没什么好注释的
mAppInfo = intent.getParcelableExtra(PackageUtil.INTENT_ATTR_APPLICATION_INFO);
mPackageURI = intent.getData();

final String scheme = mPackageURI.getScheme();
if (scheme != null && !"file".equals(scheme) && !"package".equals(scheme)) {
throw new IllegalArgumentException("unexpected scheme " + scheme);
}

initView();
}
public void initView() {
setContentView(R.layout.op_progress);
int installFlags = 0;
PackageManager pm = getPackageManager();
try {//如果应用已被安装,设置安装模式为更新
PackageInfo pi = pm.getPackageInfo(mAppInfo.packageName,
PackageManager.GET_UNINSTALLED_PACKAGES);
if(pi != null) {
installFlags |= PackageManager.INSTALL_REPLACE_EXISTING;
}
} catch (NameNotFoundException e) {
}
if((installFlags & PackageManager.INSTALL_REPLACE_EXISTING )!= 0) {
Log.w(TAG, "Replacing package:" + mAppInfo.packageName);
}

final PackageUtil.AppSnippet as;
if ("package".equals(mPackageURI.getScheme())) {//协议类型为package,则更新程序
as = new PackageUtil.AppSnippet(pm.getApplicationLabel(mAppInfo),
pm.getApplicationIcon(mAppInfo));
} else {//为file,则安装
final File sourceFile = new File(mPackageURI.getPath());
as = PackageUtil.getAppSnippet(this, mAppInfo, sourceFile);
}
mLabel = as.label;

<span style="white-space:pre">	</span>...
...

String installerPackageName = getIntent().getStringExtra(
Intent.EXTRA_INSTALLER_PACKAGE_NAME);
Uri originatingURI = getIntent().getParcelableExtra(Intent.EXTRA_ORIGINATING_URI);
Uri referrer = getIntent().getParcelableExtra(Intent.EXTRA_REFERRER);
int originatingUid = getIntent().getIntExtra(Intent.EXTRA_ORIGINATING_UID,
VerificationParams.NO_UID);
ManifestDigest manifestDigest = getIntent().getParcelableExtra(EXTRA_MANIFEST_DIGEST);
VerificationParams verificationParams = new VerificationParams(null, originatingURI,
referrer, originatingUid, manifestDigest);
PackageInstallObserver observer = new PackageInstallObserver();

if ("package".equals(mPackageURI.getScheme())) {
try {//更新应用
pm.installExistingPackage(mAppInfo.packageName);
observer.packageInstalled(mAppInfo.packageName,
PackageManager.INSTALL_SUCCEEDED);
} catch (PackageManager.NameNotFoundException e) {
observer.packageInstalled(mAppInfo.packageName,
PackageManager.INSTALL_FAILED_INVALID_APK);
}
} else {//安装应用
pm.installPackageWithVerificationAndEncryption(mPackageURI, observer, installFlags,
installerPackageName, verificationParams, null);
}
}
initView代码看起来很多,核心也就两句
pm.installExistingPackage(mAppInfo.packageName);以及
pm.installPackageWithVerificationAndEncryption(mPackageURI, observer, installFlags,
installerPackageName, verificationParams, null);这两个都是静默方法,执行过程中不会有提示
在InstallAppProgress中内嵌了一个类,用于提供给用户一个反馈

class PackageInstallObserver extends IPackageInstallObserver.Stub {
public void packageInstalled(String packageName, int returnCode) {
Message msg = mHandler.obtainMessage(INSTALL_COMPLETE);
msg.arg1 = returnCode;
mHandler.sendMessage(msg);
}
}待续
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: