編輯:關於Android編程
今天簡單講解一下PackageInstaller
文件路徑:
下面開始講解:
首先,我們說一下安裝apk的幾種方式,整體上可以分為2類,一類是有界面安裝,一類是無界面安裝。無界面安裝分為內置apk開機安裝和命令安裝,命令安裝又分為兩類,一類電腦安裝也就是adb命令,另一類是手機安裝也就是pm命令。今天我們主要介紹有界面安裝。
當然,我們從這個安裝界面說起,這個界面是那個呢?就是PackageInstallerActivity這個acitvity。它是如何啟動起來的呢?我們去看看它在AndroidManifest是如何定義的
String apkFileString = Environment.getExternalStorageDirectory().getAbsolutePath()+/.../packageName.pac; File apkFile = new File(apkFileString); Intent intent = new Intent(Intent.ACTION_VIEW); intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); intent.setDataAndType(Uri.fromFile(apkFile), application/vnd.android.package-archive); mContext.startActivity(intent);
final Intent intent = getIntent(); mPackageURI = intent.getData(); mPm = getPackageManager(); mPkgInfo = PackageUtil.getPackageInfo(mPackageURI);
獲取到,我們剛才傳進來的apkFile的Uri給了mPackageURI,接著獲取到PackageManager,然後生成一個mPkgInfo也就是PackageParser.Package,這個很重要。我們看看PackageParser.Package是如何生成的,PackageParser.Package裡面都包含了什麼東西。那我們就要去PackageUtil.getPackageInfo中了
public static PackageParser.Package getPackageInfo(Uri packageURI) { final String archiveFilePath = packageURI.getPath(); PackageParser packageParser = new PackageParser(archiveFilePath); File sourceFile = new File(archiveFilePath); DisplayMetrics metrics = new DisplayMetrics(); metrics.setToDefaults(); PackageParser.Package pkg = packageParser.parsePackage(sourceFile, archiveFilePath, metrics, 0); // Nuke the parser reference. packageParser = null; return pkg; }
public Package parsePackage(File sourceFile, String destCodePath, DisplayMetrics metrics, int flags) { mParseError = PackageManager.INSTALL_SUCCEEDED; mArchiveSourcePath = sourceFile.getPath(); if (!sourceFile.isFile()) { Slog.w(TAG, Skipping dir: + mArchiveSourcePath); mParseError = PackageManager.INSTALL_PARSE_FAILED_NOT_APK; return null; } if (!isPackageFilename(sourceFile.getName()) && (flags&PARSE_MUST_BE_APK) != 0) { if ((flags&PARSE_IS_SYSTEM) == 0) { // We expect to have non-.apk files in the system dir, // so don't warn about them. Slog.w(TAG, Skipping non-package file: + mArchiveSourcePath); } mParseError = PackageManager.INSTALL_PARSE_FAILED_NOT_APK; return null; } if (DEBUG_JAR) Slog.d(TAG, Scanning package: + mArchiveSourcePath); XmlResourceParser parser = null; AssetManager assmgr = null; Resources res = null; boolean assetError = true; try { assmgr = new AssetManager(); int cookie = assmgr.addAssetPath(mArchiveSourcePath); if (cookie != 0) { res = new Resources(assmgr, metrics, null); assmgr.setConfiguration(0, 0, null, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, Build.VERSION.RESOURCES_SDK_INT); parser = assmgr.openXmlResourceParser(cookie, ANDROID_MANIFEST_FILENAME); assetError = false; } else { Slog.w(TAG, Failed adding asset path:+mArchiveSourcePath); } } catch (Exception e) { Slog.w(TAG, Unable to read AndroidManifest.xml of + mArchiveSourcePath, e); } if (assetError) { if (assmgr != null) assmgr.close(); mParseError = PackageManager.INSTALL_PARSE_FAILED_BAD_MANIFEST; return null; } String[] errorText = new String[1]; Package pkg = null; Exception errorException = null; try { // XXXX todo: need to figure out correct configuration. pkg = parsePackage(res, parser, flags, errorText); } catch (Exception e) { errorException = e; mParseError = PackageManager.INSTALL_PARSE_FAILED_UNEXPECTED_EXCEPTION; } if (pkg == null) { // If we are only parsing core apps, then a null with INSTALL_SUCCEEDED // just means to skip this app so don't make a fuss about it. if (!mOnlyCoreApps || mParseError != PackageManager.INSTALL_SUCCEEDED) { if (errorException != null) { Slog.w(TAG, mArchiveSourcePath, errorException); } else { Slog.w(TAG, mArchiveSourcePath + (at + parser.getPositionDescription() + ): + errorText[0]); } if (mParseError == PackageManager.INSTALL_SUCCEEDED) { mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED; } } parser.close(); assmgr.close(); return null; } parser.close(); assmgr.close(); // Set code and resource paths pkg.mPath = destCodePath; pkg.mScanPath = mArchiveSourcePath; //pkg.applicationInfo.sourceDir = destCodePath; //pkg.applicationInfo.publicSourceDir = destRes; pkg.mSignatures = null; return pkg; }
XmlResourceParser parser = null; AssetManager assmgr = null; Resources res = null;
assmgr = new AssetManager(); int cookie = assmgr.addAssetPath(mArchiveSourcePath);
res = new Resources(assmgr, metrics, null);當然Resources信息也是通過AssetManager獲取到的。XmlResourceParser顧名思義就是Xml資源文件解析器了,用來解析我們xml文件的
parser = assmgr.openXmlResourceParser(cookie, ANDROID_MANIFEST_FILENAME);
private static final String ANDROID_MANIFEST_FILENAME = AndroidManifest.xml;
String[] errorText = new String[1]; Package pkg = null; Exception errorException = null; try { // XXXX todo: need to figure out correct configuration. pkg = parsePackage(res, parser, flags, errorText); } catch (Exception e) { errorException = e; mParseError = PackageManager.INSTALL_PARSE_FAILED_UNEXPECTED_EXCEPTION; }
String pkgName = parsePackageName(parser, attrs, flags, outError);
final Package pkg = new Package(pkgName); boolean foundApp = false; TypedArray sa = res.obtainAttributes(attrs, com.android.internal.R.styleable.AndroidManifest); pkg.mVersionCode = sa.getInteger( com.android.internal.R.styleable.AndroidManifest_versionCode, 0); pkg.mVersionName = sa.getNonConfigurationString( com.android.internal.R.styleable.AndroidManifest_versionName, 0); if (pkg.mVersionName != null) { pkg.mVersionName = pkg.mVersionName.intern(); } String str = sa.getNonConfigurationString( com.android.internal.R.styleable.AndroidManifest_sharedUserId, 0); if (str != null && str.length() > 0) { String nameError = validateName(str, true); if (nameError != null && !android.equals(pkgName)) { outError[0] =specifies bad sharedUserId name + str + : + nameError; mParseError = PackageManager.INSTALL_PARSE_FAILED_BAD_SHARED_USER_ID; return null; } pkg.mSharedUserId = str.intern(); pkg.mSharedUserLabel = sa.getResourceId( com.android.internal.R.styleable.AndroidManifest_sharedUserLabel, 0); } sa.recycle(); pkg.installLocation = sa.getInteger( com.android.internal.R.styleable.AndroidManifest_installLocation, PARSE_DEFAULT_INSTALL_LOCATION); pkg.applicationInfo.installLocation = pkg.installLocation;
這裡面包含的信息,例如這裡的lable等等,還有以其為父的activity,receiver,service,provider等等,這裡以activity為例,還是去frameworks/base/core/res/res/values下的attrs_manifest.xml中,也就是
這類,大家經常會見到的;還有permission-group,uses-sdk等等吧,有興趣的可以一一研究。最終這些信息都會囊括到我們的Package中。這裡我們明白Package是什麼了吧?就是包含包中所有信息的的玩意。到此位置我們的Package已經生成,然後我們還回到PackageInstallerActivity的onCreate中,接著往下看,不重要的就跳過了
initiateInstall()
也就是
private void initiateInstall() { String pkgName = mPkgInfo.packageName; // 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.setPackageName(pkgName); } // Check if package is already installed. display confirmation dialog if replacing pkg try { mAppInfo = mPm.getApplicationInfo(pkgName, PackageManager.GET_UNINSTALLED_PACKAGES); } catch (NameNotFoundException e) { mAppInfo = null; } if (mAppInfo == null || getIntent().getBooleanExtra(Intent.EXTRA_ALLOW_REPLACE, false)) { startInstallConfirm(); } else { if(localLOGV) Log.i(TAG, Replacing existing package:+ mPkgInfo.applicationInfo.packageName); showDialogInner(DLG_REPLACE_APP); } }
private void startInstallConfirm() { LinearLayout permsSection = (LinearLayout) mInstallConfirm.findViewById(R.id.permissions_section); LinearLayout securityList = (LinearLayout) permsSection.findViewById( R.id.security_settings_list); boolean permVisible = false; if(mPkgInfo != null) { AppSecurityPermissions asp = new AppSecurityPermissions(this, mPkgInfo); if(asp.getPermissionCount() > 0) { permVisible = true; securityList.addView(asp.getPermissionsView()); } } if(!permVisible){ permsSection.setVisibility(View.INVISIBLE); } mInstallConfirm.setVisibility(View.VISIBLE); mOk = (Button)findViewById(R.id.ok_button); mCancel = (Button)findViewById(R.id.cancel_button); mOk.setOnClickListener(this); mCancel.setOnClickListener(this); }
public AppSecurityPermissions(Context context, PackageParser.Package pkg) { mContext = context; mPm = mContext.getPackageManager(); mPermsList = new ArrayList(); Set permSet = new HashSet (); if(pkg == null) { return; } // Get requested permissions if (pkg.requestedPermissions != null) { ArrayList strList = pkg.requestedPermissions; int size = strList.size(); if (size > 0) { extractPerms(strList.toArray(new String[size]), permSet); } } // Get permissions related to shared user if any if(pkg.mSharedUserId != null) { int sharedUid; try { sharedUid = mPm.getUidForSharedUser(pkg.mSharedUserId); getAllUsedPermissions(sharedUid, permSet); } catch (NameNotFoundException e) { Log.w(TAG, Could'nt retrieve shared user id for:+pkg.packageName); } } // Retrieve list of permissions for(PermissionInfo tmpInfo : permSet) { mPermsList.add(tmpInfo); } }
public View getPermissionsView() { mInflater = (LayoutInflater) mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE); mPermsView = (LinearLayout) mInflater.inflate(R.layout.app_perms_summary, null); mShowMore = mPermsView.findViewById(R.id.show_more); mShowMoreIcon = (ImageView) mShowMore.findViewById(R.id.show_more_icon); mShowMoreText = (TextView) mShowMore.findViewById(R.id.show_more_text); mDangerousList = (LinearLayout) mPermsView.findViewById(R.id.dangerous_perms_list); mNonDangerousList = (LinearLayout) mPermsView.findViewById(R.id.non_dangerous_perms_list); mNoPermsView = mPermsView.findViewById(R.id.no_permissions); // Set up the LinearLayout that acts like a list item. mShowMore.setClickable(true); mShowMore.setOnClickListener(this); mShowMore.setFocusable(true); // Pick up from framework resources instead. mDefaultGrpLabel = mContext.getString(R.string.default_permission_group); mPermFormat = mContext.getString(R.string.permissions_format); mNormalIcon = mContext.getResources().getDrawable(R.drawable.ic_text_dot); mDangerousIcon = mContext.getResources().getDrawable(R.drawable.ic_bullet_key_permission); mShowMaxIcon = mContext.getResources().getDrawable(R.drawable.expander_close_holo_dark); mShowMinIcon = mContext.getResources().getDrawable(R.drawable.expander_open_holo_dark); // Set permissions view setPermissions(mPermsList); return mPermsView; }
private void setPermissions(ListpermList) { mGroupLabelCache = new HashMap (); //add the default label so that uncategorized permissions can go here mGroupLabelCache.put(mDefaultGrpName, mDefaultGrpLabel); // Map containing group names and a list of permissions under that group // categorized as dangerous mDangerousMap = new HashMap (); // Map containing group names and a list of permissions under that group // categorized as normal mNormalMap = new HashMap (); // Additional structures needed to ensure that permissions are unique under // each group Map > dangerousMap = new HashMap >(); Map > normalMap = new HashMap >(); PermissionInfoComparator permComparator = new PermissionInfoComparator(mPm); if (permList != null) { // First pass to group permissions for (PermissionInfo pInfo : permList) { if(localLOGV) Log.i(TAG, Processing permission:+pInfo.name); if(!isDisplayablePermission(pInfo)) { if(localLOGV) Log.i(TAG, Permission:+pInfo.name+ is not displayable); continue; } Map > permInfoMap = (pInfo.protectionLevel == PermissionInfo.PROTECTION_DANGEROUS) ? dangerousMap : normalMap; String grpName = (pInfo.group == null) ? mDefaultGrpName : pInfo.group; if(localLOGV) Log.i(TAG, Permission:+pInfo.name+ belongs to group:+grpName); List grpPermsList = permInfoMap.get(grpName); if(grpPermsList == null) { grpPermsList = new ArrayList (); permInfoMap.put(grpName, grpPermsList); grpPermsList.add(pInfo); } else { int idx = Collections.binarySearch(grpPermsList, pInfo, permComparator); if(localLOGV) Log.i(TAG, idx=+idx+, list.size=+grpPermsList.size()); if (idx < 0) { idx = -idx-1; grpPermsList.add(idx, pInfo); } } } // Second pass to actually form the descriptions // Look at dangerous permissions first aggregateGroupDescs(dangerousMap, mDangerousMap); aggregateGroupDescs(normalMap, mNormalMap); } mCurrentState = State.NO_PERMS; if(mDangerousMap.size() > 0) { mCurrentState = (mNormalMap.size() > 0) ? State.BOTH : State.DANGEROUS_ONLY; } else if(mNormalMap.size() > 0) { mCurrentState = State.NORMAL_ONLY; } if(localLOGV) Log.i(TAG, mCurrentState= + mCurrentState); showPermissions(); }
private void showPermissions() { switch(mCurrentState) { case NO_PERMS: displayNoPermissions(); break; case DANGEROUS_ONLY: displayPermissions(true); break; case NORMAL_ONLY: displayPermissions(false); break; case BOTH: displayPermissions(true); if (mExpanded) { displayPermissions(false); mShowMoreIcon.setImageDrawable(mShowMaxIcon); mShowMoreText.setText(R.string.perms_hide); mNonDangerousList.setVisibility(View.VISIBLE); } else { mShowMoreIcon.setImageDrawable(mShowMinIcon); mShowMoreText.setText(R.string.perms_show_all); mNonDangerousList.setVisibility(View.GONE); } mShowMore.setVisibility(View.VISIBLE); break; } }
private void displayPermissions(boolean dangerous) { MappermInfoMap = dangerous ? mDangerousMap : mNormalMap; LinearLayout permListView = dangerous ? mDangerousList : mNonDangerousList; permListView.removeAllViews(); Set permInfoStrSet = permInfoMap.keySet(); for (String loopPermGrpInfoStr : permInfoStrSet) { CharSequence grpLabel = getGroupLabel(loopPermGrpInfoStr); //guaranteed that grpLabel wont be null since permissions without groups //will belong to the default group if(localLOGV) Log.i(TAG, Adding view group: + grpLabel + , desc: + permInfoMap.get(loopPermGrpInfoStr)); permListView.addView(getPermissionItemView(grpLabel, permInfoMap.get(loopPermGrpInfoStr), dangerous)); } }
接下來,我們說說當點擊“安裝”之後做了什麼事情。
public void onClick(View v) { if(v == mOk) { // 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); String installerPackageName = getIntent().getStringExtra(Intent.EXTRA_INSTALLER_PACKAGE_NAME); 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); finish(); } else if(v == mCancel) { // Cancel and finish setResult(RESULT_CANCELED); finish(); } }
@Override public void onCreate(Bundle icicle) { super.onCreate(icicle); Intent intent = getIntent(); mAppInfo = intent.getParcelableExtra(PackageUtil.INTENT_ATTR_APPLICATION_INFO); mPackageURI = intent.getData(); initView(); }
String installerPackageName = getIntent().getStringExtra( Intent.EXTRA_INSTALLER_PACKAGE_NAME); PackageInstallObserver observer = new PackageInstallObserver(); pm.installPackage(mPackageURI, observer, installFlags, installerPackageName);
class PackageInstallObserver extends IPackageInstallObserver.Stub { public void packageInstalled(String packageName, int returnCode) { Message msg = mHandler.obtainMessage(INSTALL_COMPLETE); Log.d(packageInstalled, returnCode = +returnCode); msg.arg1 = returnCode; mHandler.sendMessage(msg); } }
/* Called when a downloaded package installation has been confirmed by the user */ public void installPackage( final Uri packageURI, final IPackageInstallObserver observer, final int flags) { installPackage(packageURI, observer, flags, null); } /* Called when a downloaded package installation has been confirmed by the user */ public void installPackage( final Uri packageURI, final IPackageInstallObserver observer, final int flags, final String installerPackageName) { installPackageWithVerification(packageURI, observer, flags, installerPackageName, null, null); }
public void installPackageWithVerification(Uri packageURI, IPackageInstallObserver observer, int flags, String installerPackageName, Uri verificationURI, ManifestDigest manifestDigest) { mContext.enforceCallingOrSelfPermission(android.Manifest.permission.INSTALL_PACKAGES, null); final int uid = Binder.getCallingUid(); final int filteredFlags; if (uid == Process.SHELL_UID || uid == 0) { if (DEBUG_INSTALL) { Slog.v(TAG, Install from ADB); } filteredFlags = flags | PackageManager.INSTALL_FROM_ADB; } else { filteredFlags = flags & ~PackageManager.INSTALL_FROM_ADB; } final Message msg = mHandler.obtainMessage(INIT_COPY); msg.obj = new InstallParams(packageURI, observer, filteredFlags, installerPackageName, verificationURI, manifestDigest); mHandler.sendMessage(msg); }
case INIT_COPY: { if (DEBUG_INSTALL) Slog.i(TAG, init_copy); HandlerParams params = (HandlerParams) msg.obj; int idx = mPendingInstalls.size(); if (DEBUG_INSTALL) Slog.i(TAG, idx= + idx); // If a bind was already initiated we dont really // need to do anything. The pending install // will be processed later on. if (!mBound) { // If this is the only one pending we might // have to bind to the service again. if (!connectToService()) { Slog.e(TAG, Failed to bind to media container service); params.serviceError(); return; } else { // Once we bind to the service, the first // pending request will be processed. mPendingInstalls.add(idx, params); } } else { mPendingInstalls.add(idx, params); // Already bound to the service. Just make // sure we trigger off processing the first request. if (idx == 0) { mHandler.sendEmptyMessage(MCS_BOUND); } } break; }
case MCS_BOUND: { if (DEBUG_INSTALL) Slog.i(TAG, mcs_bound); if (msg.obj != null) { mContainerService = (IMediaContainerService) msg.obj; } if (mContainerService == null) { // Something seriously wrong. Bail out Slog.e(TAG, Cannot bind to media container service); for (HandlerParams params : mPendingInstalls) { mPendingInstalls.remove(0); // Indicate service bind error params.serviceError(); } mPendingInstalls.clear(); } else if (mPendingInstalls.size() > 0) { HandlerParams params = mPendingInstalls.get(0); if (params != null) { if (params.startCopy()) { // We are done... look for more work or to // go idle. if (DEBUG_SD_INSTALL) Log.i(TAG, Checking for more work or unbind...); // Delete pending install if (mPendingInstalls.size() > 0) { mPendingInstalls.remove(0); } if (mPendingInstalls.size() == 0) { if (mBound) { if (DEBUG_SD_INSTALL) Log.i(TAG, Posting delayed MCS_UNBIND); removeMessages(MCS_UNBIND); Message ubmsg = obtainMessage(MCS_UNBIND); // Unbind after a little delay, to avoid // continual thrashing. sendMessageDelayed(ubmsg, 10000); } } else { // There are more pending requests in queue. // Just post MCS_BOUND message to trigger processing // of next pending install. if (DEBUG_SD_INSTALL) Log.i(TAG, Posting MCS_BOUND for next woek); mHandler.sendEmptyMessage(MCS_BOUND); } } } } else { // Should never happen ideally. Slog.w(TAG, Empty queue); } break; }
params.startCopy()
這個了,進去看看
final boolean startCopy() { boolean res; try { if (DEBUG_INSTALL) Slog.i(TAG, startCopy); if (++mRetries > MAX_RETRIES) { Slog.w(TAG, Failed to invoke remote methods on default container service. Giving up); mHandler.sendEmptyMessage(MCS_GIVE_UP); handleServiceError(); return false; } else { handleStartCopy(); res = true; } } catch (RemoteException e) { if (DEBUG_INSTALL) Slog.i(TAG, Posting install MCS_RECONNECT); mHandler.sendEmptyMessage(MCS_RECONNECT); res = false; } handleReturnCode(); return res; }
這裡的handleStartCopy()和handleServiceError()和handleReturnCode()都是abstract函數,希望大家還記得剛才我們發消息的時候攜帶的是InstallParams個類,InstallParams繼承於HandlerParams,所以我們就會知道這三個abstract是在哪裡實現的了,我們先說說handleStartCopy(),主要給兩個變量完成了賦值工作也個是mArgs也就是InstallArgs,一個是ret標識是否安裝成功的。handleServiceError()這個不講解,然後看handleReturnCode()
@Override void handleReturnCode() { // If mArgs is null, then MCS couldn't be reached. When it // reconnects, it will try again to install. At that point, this // will succeed. if (mArgs != null) { processPendingInstall(mArgs, mRet); } }
private void processPendingInstall(final InstallArgs args, final int currentStatus) { // Queue up an async operation since the package installation may take a little while. mHandler.post(new Runnable() { public void run() { mHandler.removeCallbacks(this); // Result object to be returned PackageInstalledInfo res = new PackageInstalledInfo(); res.returnCode = currentStatus; res.uid = -1; res.pkg = null; res.removedInfo = new PackageRemovedInfo(); if (res.returnCode == PackageManager.INSTALL_SUCCEEDED) { args.doPreInstall(res.returnCode); synchronized (mInstallLock) { installPackageLI(args, true, res); } args.doPostInstall(res.returnCode); } // A restore should be performed at this point if (a) the install // succeeded, (b) the operation is not an update, and (c) the new // package has a backupAgent defined. final boolean update = res.removedInfo.removedPackage != null; boolean doRestore = (!update && res.pkg != null && res.pkg.applicationInfo.backupAgentName != null); // Set up the post-install work request bookkeeping. This will be used // and cleaned up by the post-install event handling regardless of whether // there's a restore pass performed. Token values are >= 1. int token; if (mNextInstallToken < 0) mNextInstallToken = 1; token = mNextInstallToken++; PostInstallData data = new PostInstallData(args, res); mRunningInstalls.put(token, data); if (DEBUG_INSTALL) Log.v(TAG, + starting restore round-trip + token); if (res.returnCode == PackageManager.INSTALL_SUCCEEDED && doRestore) { // Pass responsibility to the Backup Manager. It will perform a // restore if appropriate, then pass responsibility back to the // Package Manager to run the post-install observer callbacks // and broadcasts. IBackupManager bm = IBackupManager.Stub.asInterface( ServiceManager.getService(Context.BACKUP_SERVICE)); if (bm != null) { if (DEBUG_INSTALL) Log.v(TAG, token + token + to BM for possible restore); try { bm.restoreAtInstall(res.pkg.applicationInfo.packageName, token); } catch (RemoteException e) { // can't happen; the backup manager is local } catch (Exception e) { Slog.e(TAG, Exception trying to enqueue restore, e); doRestore = false; } } else { Slog.e(TAG, Backup Manager not found!); doRestore = false; } } if (!doRestore) { // No restore possible, or the Backup Manager was mysteriously not // available -- just fire the post-install work request directly. if (DEBUG_INSTALL) Log.v(TAG, No restore - queue post-install for + token); Message msg = mHandler.obtainMessage(POST_INSTALL, token, 0); mHandler.sendMessage(msg); } } }); }
PackageInstalledInfo res = new PackageInstalledInfo(); res.returnCode = currentStatus; res.uid = -1; res.pkg = null; res.removedInfo = new PackageRemovedInfo(); if (res.returnCode == PackageManager.INSTALL_SUCCEEDED) { args.doPreInstall(res.returnCode); synchronized (mInstallLock) { installPackageLI(args, true, res); } args.doPostInstall(res.returnCode); }
if (replace) { replacePackageLI(pkg, parseFlags, scanMode, installerPackageName, res); } else { installNewPackageLI(pkg, parseFlags, scanMode, installerPackageName,res); }
/* * Install a non-existing package. */ private void installNewPackageLI(PackageParser.Package pkg, int parseFlags, int scanMode, String installerPackageName, PackageInstalledInfo res) { // Remember this for later, in case we need to rollback this install String pkgName = pkg.packageName; boolean dataDirExists = getDataPathForPackage(pkg.packageName, 0).exists(); res.name = pkgName; 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. Slog.w(TAG, Attempt to re-install + pkgName + without first uninstalling package running as + mSettings.mRenamedPackages.get(pkgName)); res.returnCode = PackageManager.INSTALL_FAILED_ALREADY_EXISTS; return; } if (mPackages.containsKey(pkgName) || mAppDirs.containsKey(pkg.mPath)) { // Don't allow installation over an existing package with the same name. Slog.w(TAG, Attempt to re-install + pkgName + without first uninstalling.); res.returnCode = PackageManager.INSTALL_FAILED_ALREADY_EXISTS; return; } } mLastScanError = PackageManager.INSTALL_SUCCEEDED; PackageParser.Package newPackage = scanPackageLI(pkg, parseFlags, scanMode, System.currentTimeMillis()); if (newPackage == null) { Slog.w(TAG, Package couldn't be installed in + pkg.mPath); if ((res.returnCode=mLastScanError) == PackageManager.INSTALL_SUCCEEDED) { res.returnCode = PackageManager.INSTALL_FAILED_INVALID_APK; } } else { updateSettingsLI(newPackage, installerPackageName, 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, false, dataDirExists ? PackageManager.DONT_DELETE_DATA : 0, res.removedInfo, true); } } }
PackageParser.Package newPackage = scanPackageLI(pkg, parseFlags, scanMode, System.currentTimeMillis());
int ret = mInstaller.install(pkgName, pkg.applicationInfo.uid, pkg.applicationInfo.uid);
public int install(String name, int uid, int gid) { StringBuilder builder = new StringBuilder(install); builder.append(' '); builder.append(name); builder.append(' '); builder.append(uid); builder.append(' '); builder.append(gid); return execute(builder.toString()); }
private int execute(String cmd) { String res = transaction(cmd); try { return Integer.parseInt(res); } catch (NumberFormatException ex) { return -1; } }
private synchronized String transaction(String cmd) { if (!connect()) { Slog.e(TAG, connection failed); return -1; } if (!writeCommand(cmd)) { /* * If installd died and restarted in the background (unlikely but * possible) we'll fail on the next write (this one). Try to * reconnect and write the command one more time before giving up. */ Slog.e(TAG, write command failed? reconnect!); if (!connect() || !writeCommand(cmd)) { return -1; } } if (LOCAL_DEBUG) { Slog.i(TAG, send: ' + cmd + '); } if (readReply()) { String s = new String(buf, 0, buflen); if (LOCAL_DEBUG) { Slog.i(TAG, recv: ' + s + '); } return s; } else { if (LOCAL_DEBUG) { Slog.i(TAG, fail); } return -1; } }
private boolean writeCommand(String _cmd) { byte[] cmd = _cmd.getBytes(); int len = cmd.length; if ((len < 1) || (len > 1024)) return false; buf[0] = (byte) (len & 0xff); buf[1] = (byte) ((len >> 8) & 0xff); try { mOut.write(buf, 0, 2); mOut.write(cmd, 0, len); } catch (IOException ex) { Slog.e(TAG, write error); disconnect(); return false; } return true; }
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; }
還是那句話給大師取樂,給後來者拋磚引玉,不要在背後罵我就謝天謝地了。
Android 實現QQ第三方登錄 在項目中需要實現QQ第三方登錄,經過一番努力算是寫出來了,現在總結以下,以防以後遺忘,能幫到其他童鞋就更好了。 首先肯定是去下載SDK
1:服務端使用PHP 復制代碼 代碼如下:<?php echo date(Y-m-d H:i:s);?>2:activit
Fragment相當於一個小型activity,因為Fragment可以實現activity中所有的功能,不同的是Fragment可以嵌入activity,一個activ
版本:1.0 日期:2014.8.9 2014.9.24版權:© 2014 kince 轉載注明出處 波形效果有幾種不同的呈現形式,比如從中間向四周散開的波形,