Home | History | Annotate | Download | only in packageinstaller
      1 /*
      2 **
      3 ** Copyright 2007, The Android Open Source Project
      4 **
      5 ** Licensed under the Apache License, Version 2.0 (the "License");
      6 ** you may not use this file except in compliance with the License.
      7 ** You may obtain a copy of the License at
      8 **
      9 **     http://www.apache.org/licenses/LICENSE-2.0
     10 **
     11 ** Unless required by applicable law or agreed to in writing, software
     12 ** distributed under the License is distributed on an "AS IS" BASIS,
     13 ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     14 ** See the License for the specific language governing permissions and
     15 ** limitations under the License.
     16 */
     17 package com.android.packageinstaller;
     18 
     19 import android.app.Activity;
     20 import android.app.ActivityManagerNative;
     21 import android.app.AlertDialog;
     22 import android.app.Dialog;
     23 import android.content.Context;
     24 import android.content.DialogInterface;
     25 import android.content.DialogInterface.OnCancelListener;
     26 import android.content.Intent;
     27 import android.content.SharedPreferences;
     28 import android.content.pm.ApplicationInfo;
     29 import android.content.pm.ManifestDigest;
     30 import android.content.pm.PackageInfo;
     31 import android.content.pm.PackageInstaller;
     32 import android.content.pm.PackageManager;
     33 import android.content.pm.PackageManager.NameNotFoundException;
     34 import android.content.pm.PackageParser;
     35 import android.content.pm.PackageUserState;
     36 import android.content.pm.ResolveInfo;
     37 import android.content.pm.VerificationParams;
     38 import android.net.Uri;
     39 import android.os.Bundle;
     40 import android.os.SystemClock;
     41 import android.os.UserManager;
     42 import android.provider.Settings;
     43 import android.support.v4.view.ViewPager;
     44 import android.util.Log;
     45 import android.view.LayoutInflater;
     46 import android.view.View;
     47 import android.view.View.OnClickListener;
     48 import android.view.ViewGroup;
     49 import android.widget.AppSecurityPermissions;
     50 import android.widget.Button;
     51 import android.widget.TabHost;
     52 import android.widget.TextView;
     53 
     54 import java.io.File;
     55 import java.util.List;
     56 
     57 /*
     58  * This activity is launched when a new application is installed via side loading
     59  * The package is first parsed and the user is notified of parse errors via a dialog.
     60  * If the package is successfully parsed, the user is notified to turn on the install unknown
     61  * applications setting. A memory check is made at this point and the user is notified of out
     62  * of memory conditions if any. If the package is already existing on the device,
     63  * a confirmation dialog (to replace the existing package) is presented to the user.
     64  * Based on the user response the package is then installed by launching InstallAppConfirm
     65  * sub activity. All state transitions are handled in this activity
     66  */
     67 public class PackageInstallerActivity extends Activity implements OnCancelListener, OnClickListener {
     68     private static final String TAG = "PackageInstaller";
     69 
     70     private int mSessionId = -1;
     71     private Uri mPackageURI;
     72     private Uri mOriginatingURI;
     73     private Uri mReferrerURI;
     74     private int mOriginatingUid = VerificationParams.NO_UID;
     75     private ManifestDigest mPkgDigest;
     76 
     77     private boolean localLOGV = false;
     78     PackageManager mPm;
     79     PackageInstaller mInstaller;
     80     PackageInfo mPkgInfo;
     81     ApplicationInfo mSourceInfo;
     82 
     83     // ApplicationInfo object primarily used for already existing applications
     84     private ApplicationInfo mAppInfo = null;
     85 
     86     private InstallFlowAnalytics mInstallFlowAnalytics;
     87 
     88     // View for install progress
     89     View mInstallConfirm;
     90     // Buttons to indicate user acceptance
     91     private Button mOk;
     92     private Button mCancel;
     93     CaffeinatedScrollView mScrollView = null;
     94     private boolean mOkCanInstall = false;
     95 
     96     static final String PREFS_ALLOWED_SOURCES = "allowed_sources";
     97 
     98     private static final String PACKAGE_MIME_TYPE = "application/vnd.android.package-archive";
     99 
    100     private static final String TAB_ID_ALL = "all";
    101     private static final String TAB_ID_NEW = "new";
    102 
    103     // Dialog identifiers used in showDialog
    104     private static final int DLG_BASE = 0;
    105     private static final int DLG_UNKNOWN_APPS = DLG_BASE + 1;
    106     private static final int DLG_PACKAGE_ERROR = DLG_BASE + 2;
    107     private static final int DLG_OUT_OF_SPACE = DLG_BASE + 3;
    108     private static final int DLG_INSTALL_ERROR = DLG_BASE + 4;
    109     private static final int DLG_ALLOW_SOURCE = DLG_BASE + 5;
    110 
    111     private void startInstallConfirm() {
    112         TabHost tabHost = (TabHost)findViewById(android.R.id.tabhost);
    113         tabHost.setup();
    114         ViewPager viewPager = (ViewPager)findViewById(R.id.pager);
    115         TabsAdapter adapter = new TabsAdapter(this, tabHost, viewPager);
    116         adapter.setOnTabChangedListener(new TabHost.OnTabChangeListener() {
    117             @Override
    118             public void onTabChanged(String tabId) {
    119                 if (TAB_ID_ALL.equals(tabId)) {
    120                     mInstallFlowAnalytics.setAllPermissionsDisplayed(true);
    121                 } else if (TAB_ID_NEW.equals(tabId)) {
    122                     mInstallFlowAnalytics.setNewPermissionsDisplayed(true);
    123                 }
    124             }
    125         });
    126 
    127         boolean permVisible = false;
    128         mScrollView = null;
    129         mOkCanInstall = false;
    130         int msg = 0;
    131         if (mPkgInfo != null) {
    132             AppSecurityPermissions perms = new AppSecurityPermissions(this, mPkgInfo);
    133             final int NP = perms.getPermissionCount(AppSecurityPermissions.WHICH_PERSONAL);
    134             final int ND = perms.getPermissionCount(AppSecurityPermissions.WHICH_DEVICE);
    135             if (mAppInfo != null) {
    136                 msg = (mAppInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0
    137                         ? R.string.install_confirm_question_update_system
    138                         : R.string.install_confirm_question_update;
    139                 mScrollView = new CaffeinatedScrollView(this);
    140                 mScrollView.setFillViewport(true);
    141                 boolean newPermissionsFound =
    142                         (perms.getPermissionCount(AppSecurityPermissions.WHICH_NEW) > 0);
    143                 mInstallFlowAnalytics.setNewPermissionsFound(newPermissionsFound);
    144                 if (newPermissionsFound) {
    145                     permVisible = true;
    146                     mScrollView.addView(perms.getPermissionsView(
    147                             AppSecurityPermissions.WHICH_NEW));
    148                 } else {
    149                     LayoutInflater inflater = (LayoutInflater)getSystemService(
    150                             Context.LAYOUT_INFLATER_SERVICE);
    151                     TextView label = (TextView)inflater.inflate(R.layout.label, null);
    152                     label.setText(R.string.no_new_perms);
    153                     mScrollView.addView(label);
    154                 }
    155                 adapter.addTab(tabHost.newTabSpec(TAB_ID_NEW).setIndicator(
    156                         getText(R.string.newPerms)), mScrollView);
    157             } else  {
    158                 findViewById(R.id.tabscontainer).setVisibility(View.GONE);
    159                 findViewById(R.id.divider).setVisibility(View.VISIBLE);
    160             }
    161             if (NP > 0 || ND > 0) {
    162                 permVisible = true;
    163                 LayoutInflater inflater = (LayoutInflater)getSystemService(
    164                         Context.LAYOUT_INFLATER_SERVICE);
    165                 View root = inflater.inflate(R.layout.permissions_list, null);
    166                 if (mScrollView == null) {
    167                     mScrollView = (CaffeinatedScrollView)root.findViewById(R.id.scrollview);
    168                 }
    169                 if (NP > 0) {
    170                     ((ViewGroup)root.findViewById(R.id.privacylist)).addView(
    171                             perms.getPermissionsView(AppSecurityPermissions.WHICH_PERSONAL));
    172                 } else {
    173                     root.findViewById(R.id.privacylist).setVisibility(View.GONE);
    174                 }
    175                 if (ND > 0) {
    176                     ((ViewGroup)root.findViewById(R.id.devicelist)).addView(
    177                             perms.getPermissionsView(AppSecurityPermissions.WHICH_DEVICE));
    178                 } else {
    179                     root.findViewById(R.id.devicelist).setVisibility(View.GONE);
    180                 }
    181                 adapter.addTab(tabHost.newTabSpec(TAB_ID_ALL).setIndicator(
    182                         getText(R.string.allPerms)), root);
    183             }
    184         }
    185         mInstallFlowAnalytics.setPermissionsDisplayed(permVisible);
    186         if (!permVisible) {
    187             if (mAppInfo != null) {
    188                 // This is an update to an application, but there are no
    189                 // permissions at all.
    190                 msg = (mAppInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0
    191                         ? R.string.install_confirm_question_update_system_no_perms
    192                         : R.string.install_confirm_question_update_no_perms;
    193             } else {
    194                 // This is a new application with no permissions.
    195                 msg = R.string.install_confirm_question_no_perms;
    196             }
    197             tabHost.setVisibility(View.GONE);
    198             mInstallFlowAnalytics.setAllPermissionsDisplayed(false);
    199             mInstallFlowAnalytics.setNewPermissionsDisplayed(false);
    200             findViewById(R.id.filler).setVisibility(View.VISIBLE);
    201             findViewById(R.id.divider).setVisibility(View.GONE);
    202             mScrollView = null;
    203         }
    204         if (msg != 0) {
    205             ((TextView)findViewById(R.id.install_confirm_question)).setText(msg);
    206         }
    207         mInstallConfirm.setVisibility(View.VISIBLE);
    208         mOk = (Button)findViewById(R.id.ok_button);
    209         mCancel = (Button)findViewById(R.id.cancel_button);
    210         mOk.setOnClickListener(this);
    211         mCancel.setOnClickListener(this);
    212         if (mScrollView == null) {
    213             // There is nothing to scroll view, so the ok button is immediately
    214             // set to install.
    215             mOk.setText(R.string.install);
    216             mOkCanInstall = true;
    217         } else {
    218             mScrollView.setFullScrollAction(new Runnable() {
    219                 @Override
    220                 public void run() {
    221                     mOk.setText(R.string.install);
    222                     mOkCanInstall = true;
    223                 }
    224             });
    225         }
    226     }
    227 
    228     private void showDialogInner(int id) {
    229         // TODO better fix for this? Remove dialog so that it gets created again
    230         removeDialog(id);
    231         showDialog(id);
    232     }
    233 
    234     @Override
    235     public Dialog onCreateDialog(int id, Bundle bundle) {
    236         switch (id) {
    237         case DLG_UNKNOWN_APPS:
    238             return new AlertDialog.Builder(this)
    239                     .setTitle(R.string.unknown_apps_dlg_title)
    240                     .setMessage(R.string.unknown_apps_dlg_text)
    241                     .setNegativeButton(R.string.cancel, new DialogInterface.OnClickListener() {
    242                         public void onClick(DialogInterface dialog, int which) {
    243                             Log.i(TAG, "Finishing off activity so that user can navigate to settings manually");
    244                             finish();
    245                         }})
    246                     .setPositiveButton(R.string.settings, new DialogInterface.OnClickListener() {
    247                         public void onClick(DialogInterface dialog, int which) {
    248                             Log.i(TAG, "Launching settings");
    249                             launchSettingsAppAndFinish();
    250                         }
    251                     })
    252                     .setOnCancelListener(this)
    253                     .create();
    254         case DLG_PACKAGE_ERROR :
    255             return new AlertDialog.Builder(this)
    256                     .setTitle(R.string.Parse_error_dlg_title)
    257                     .setMessage(R.string.Parse_error_dlg_text)
    258                     .setPositiveButton(R.string.ok, new DialogInterface.OnClickListener() {
    259                         public void onClick(DialogInterface dialog, int which) {
    260                             finish();
    261                         }
    262                     })
    263                     .setOnCancelListener(this)
    264                     .create();
    265         case DLG_OUT_OF_SPACE:
    266             // Guaranteed not to be null. will default to package name if not set by app
    267             CharSequence appTitle = mPm.getApplicationLabel(mPkgInfo.applicationInfo);
    268             String dlgText = getString(R.string.out_of_space_dlg_text,
    269                     appTitle.toString());
    270             return new AlertDialog.Builder(this)
    271                     .setTitle(R.string.out_of_space_dlg_title)
    272                     .setMessage(dlgText)
    273                     .setPositiveButton(R.string.manage_applications, new DialogInterface.OnClickListener() {
    274                         public void onClick(DialogInterface dialog, int which) {
    275                             //launch manage applications
    276                             Intent intent = new Intent("android.intent.action.MANAGE_PACKAGE_STORAGE");
    277                             intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
    278                             startActivity(intent);
    279                             finish();
    280                         }
    281                     })
    282                     .setNegativeButton(R.string.cancel, new DialogInterface.OnClickListener() {
    283                         public void onClick(DialogInterface dialog, int which) {
    284                             Log.i(TAG, "Canceling installation");
    285                             finish();
    286                         }
    287                   })
    288                   .setOnCancelListener(this)
    289                   .create();
    290         case DLG_INSTALL_ERROR :
    291             // Guaranteed not to be null. will default to package name if not set by app
    292             CharSequence appTitle1 = mPm.getApplicationLabel(mPkgInfo.applicationInfo);
    293             String dlgText1 = getString(R.string.install_failed_msg,
    294                     appTitle1.toString());
    295             return new AlertDialog.Builder(this)
    296                     .setTitle(R.string.install_failed)
    297                     .setNeutralButton(R.string.ok, new DialogInterface.OnClickListener() {
    298                         public void onClick(DialogInterface dialog, int which) {
    299                             finish();
    300                         }
    301                     })
    302                     .setMessage(dlgText1)
    303                     .setOnCancelListener(this)
    304                     .create();
    305         case DLG_ALLOW_SOURCE:
    306             CharSequence appTitle2 = mPm.getApplicationLabel(mSourceInfo);
    307             String dlgText2 = getString(R.string.allow_source_dlg_text,
    308                     appTitle2.toString());
    309             return new AlertDialog.Builder(this)
    310                     .setTitle(R.string.allow_source_dlg_title)
    311                     .setMessage(dlgText2)
    312                     .setNegativeButton(R.string.cancel, new DialogInterface.OnClickListener() {
    313                         public void onClick(DialogInterface dialog, int which) {
    314                             setResult(RESULT_CANCELED);
    315                             finish();
    316                         }})
    317                     .setPositiveButton(R.string.ok, new DialogInterface.OnClickListener() {
    318                         public void onClick(DialogInterface dialog, int which) {
    319                             SharedPreferences prefs = getSharedPreferences(PREFS_ALLOWED_SOURCES,
    320                                     Context.MODE_PRIVATE);
    321                             prefs.edit().putBoolean(mSourceInfo.packageName, true).apply();
    322                             startInstallConfirm();
    323                         }
    324                     })
    325                     .setOnCancelListener(this)
    326                     .create();
    327        }
    328        return null;
    329    }
    330 
    331     private void launchSettingsAppAndFinish() {
    332         // Create an intent to launch SettingsTwo activity
    333         Intent launchSettingsIntent = new Intent(Settings.ACTION_SECURITY_SETTINGS);
    334         launchSettingsIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
    335         startActivity(launchSettingsIntent);
    336         finish();
    337     }
    338 
    339     private boolean isInstallingUnknownAppsAllowed() {
    340         UserManager um = (UserManager) getSystemService(USER_SERVICE);
    341 
    342         boolean disallowedByUserManager = um.getUserRestrictions()
    343                 .getBoolean(UserManager.DISALLOW_INSTALL_UNKNOWN_SOURCES, false);
    344         boolean allowedBySecureSettings = Settings.Secure.getInt(getContentResolver(),
    345             Settings.Secure.INSTALL_NON_MARKET_APPS, 0) > 0;
    346 
    347         return (allowedBySecureSettings && (!disallowedByUserManager));
    348     }
    349 
    350     private boolean isInstallRequestFromUnknownSource(Intent intent) {
    351         String callerPackage = getCallingPackage();
    352         if (callerPackage != null && intent.getBooleanExtra(
    353                 Intent.EXTRA_NOT_UNKNOWN_SOURCE, false)) {
    354             try {
    355                 mSourceInfo = mPm.getApplicationInfo(callerPackage, 0);
    356                 if (mSourceInfo != null) {
    357                     if ((mSourceInfo.flags & ApplicationInfo.FLAG_PRIVILEGED) != 0) {
    358                         // Privileged apps are not considered an unknown source.
    359                         return false;
    360                     }
    361                 }
    362             } catch (NameNotFoundException e) {
    363             }
    364         }
    365 
    366         return true;
    367     }
    368 
    369     private boolean isVerifyAppsEnabled() {
    370         UserManager um = (UserManager) getSystemService(USER_SERVICE);
    371         if (um.hasUserRestriction(UserManager.ENSURE_VERIFY_APPS)) {
    372             return true;
    373         }
    374         return Settings.Global.getInt(getContentResolver(),
    375                 Settings.Global.PACKAGE_VERIFIER_ENABLE, 1) > 0;
    376     }
    377 
    378     private boolean isAppVerifierInstalled() {
    379         final PackageManager pm = getPackageManager();
    380         final Intent verification = new Intent(Intent.ACTION_PACKAGE_NEEDS_VERIFICATION);
    381         verification.setType(PACKAGE_MIME_TYPE);
    382         verification.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
    383         final List<ResolveInfo> receivers = pm.queryBroadcastReceivers(verification, 0);
    384         return (receivers.size() > 0) ? true : false;
    385     }
    386 
    387     private void initiateInstall() {
    388         String pkgName = mPkgInfo.packageName;
    389         // Check if there is already a package on the device with this name
    390         // but it has been renamed to something else.
    391         String[] oldName = mPm.canonicalToCurrentPackageNames(new String[] { pkgName });
    392         if (oldName != null && oldName.length > 0 && oldName[0] != null) {
    393             pkgName = oldName[0];
    394             mPkgInfo.packageName = pkgName;
    395             mPkgInfo.applicationInfo.packageName = pkgName;
    396         }
    397         // Check if package is already installed. display confirmation dialog if replacing pkg
    398         try {
    399             // This is a little convoluted because we want to get all uninstalled
    400             // apps, but this may include apps with just data, and if it is just
    401             // data we still want to count it as "installed".
    402             mAppInfo = mPm.getApplicationInfo(pkgName,
    403                     PackageManager.GET_UNINSTALLED_PACKAGES);
    404             if ((mAppInfo.flags&ApplicationInfo.FLAG_INSTALLED) == 0) {
    405                 mAppInfo = null;
    406             }
    407         } catch (NameNotFoundException e) {
    408             mAppInfo = null;
    409         }
    410 
    411         mInstallFlowAnalytics.setReplace(mAppInfo != null);
    412         mInstallFlowAnalytics.setSystemApp(
    413                 (mAppInfo != null) && ((mAppInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0));
    414 
    415         startInstallConfirm();
    416     }
    417 
    418     void setPmResult(int pmResult) {
    419         Intent result = new Intent();
    420         result.putExtra(Intent.EXTRA_INSTALL_RESULT, pmResult);
    421         setResult(pmResult == PackageManager.INSTALL_SUCCEEDED
    422                 ? RESULT_OK : RESULT_FIRST_USER, result);
    423     }
    424 
    425     @Override
    426     protected void onCreate(Bundle icicle) {
    427         super.onCreate(icicle);
    428 
    429         mPm = getPackageManager();
    430         mInstaller = mPm.getPackageInstaller();
    431 
    432         final Intent intent = getIntent();
    433         if (PackageInstaller.ACTION_CONFIRM_PERMISSIONS.equals(intent.getAction())) {
    434             final int sessionId = intent.getIntExtra(PackageInstaller.EXTRA_SESSION_ID, -1);
    435             final PackageInstaller.SessionInfo info = mInstaller.getSessionInfo(sessionId);
    436             if (info == null || !info.sealed || info.resolvedBaseCodePath == null) {
    437                 Log.w(TAG, "Session " + mSessionId + " in funky state; ignoring");
    438                 finish();
    439                 return;
    440             }
    441 
    442             mSessionId = sessionId;
    443             mPackageURI = Uri.fromFile(new File(info.resolvedBaseCodePath));
    444             mOriginatingURI = null;
    445             mReferrerURI = null;
    446         } else {
    447             mSessionId = -1;
    448             mPackageURI = intent.getData();
    449             mOriginatingURI = intent.getParcelableExtra(Intent.EXTRA_ORIGINATING_URI);
    450             mReferrerURI = intent.getParcelableExtra(Intent.EXTRA_REFERRER);
    451         }
    452 
    453         boolean requestFromUnknownSource = isInstallRequestFromUnknownSource(intent);
    454         mInstallFlowAnalytics = new InstallFlowAnalytics();
    455         mInstallFlowAnalytics.setContext(this);
    456         mInstallFlowAnalytics.setStartTimestampMillis(SystemClock.elapsedRealtime());
    457         mInstallFlowAnalytics.setInstallsFromUnknownSourcesPermitted(
    458                 isInstallingUnknownAppsAllowed());
    459         mInstallFlowAnalytics.setInstallRequestFromUnknownSource(requestFromUnknownSource);
    460         mInstallFlowAnalytics.setVerifyAppsEnabled(isVerifyAppsEnabled());
    461         mInstallFlowAnalytics.setAppVerifierInstalled(isAppVerifierInstalled());
    462         mInstallFlowAnalytics.setPackageUri(mPackageURI.toString());
    463 
    464         final String scheme = mPackageURI.getScheme();
    465         if (scheme != null && !"file".equals(scheme) && !"package".equals(scheme)) {
    466             Log.w(TAG, "Unsupported scheme " + scheme);
    467             setPmResult(PackageManager.INSTALL_FAILED_INVALID_URI);
    468             mInstallFlowAnalytics.setFlowFinished(
    469                     InstallFlowAnalytics.RESULT_FAILED_UNSUPPORTED_SCHEME);
    470             finish();
    471             return;
    472         }
    473 
    474         final PackageUtil.AppSnippet as;
    475         if ("package".equals(mPackageURI.getScheme())) {
    476             mInstallFlowAnalytics.setFileUri(false);
    477             try {
    478                 mPkgInfo = mPm.getPackageInfo(mPackageURI.getSchemeSpecificPart(),
    479                         PackageManager.GET_PERMISSIONS | PackageManager.GET_UNINSTALLED_PACKAGES);
    480             } catch (NameNotFoundException e) {
    481             }
    482             if (mPkgInfo == null) {
    483                 Log.w(TAG, "Requested package " + mPackageURI.getScheme()
    484                         + " not available. Discontinuing installation");
    485                 showDialogInner(DLG_PACKAGE_ERROR);
    486                 setPmResult(PackageManager.INSTALL_FAILED_INVALID_APK);
    487                 mInstallFlowAnalytics.setPackageInfoObtained();
    488                 mInstallFlowAnalytics.setFlowFinished(
    489                         InstallFlowAnalytics.RESULT_FAILED_PACKAGE_MISSING);
    490                 return;
    491             }
    492             as = new PackageUtil.AppSnippet(mPm.getApplicationLabel(mPkgInfo.applicationInfo),
    493                     mPm.getApplicationIcon(mPkgInfo.applicationInfo));
    494         } else {
    495             mInstallFlowAnalytics.setFileUri(true);
    496             final File sourceFile = new File(mPackageURI.getPath());
    497             PackageParser.Package parsed = PackageUtil.getPackageInfo(sourceFile);
    498 
    499             // Check for parse errors
    500             if (parsed == null) {
    501                 Log.w(TAG, "Parse error when parsing manifest. Discontinuing installation");
    502                 showDialogInner(DLG_PACKAGE_ERROR);
    503                 setPmResult(PackageManager.INSTALL_FAILED_INVALID_APK);
    504                 mInstallFlowAnalytics.setPackageInfoObtained();
    505                 mInstallFlowAnalytics.setFlowFinished(
    506                         InstallFlowAnalytics.RESULT_FAILED_TO_GET_PACKAGE_INFO);
    507                 return;
    508             }
    509             mPkgInfo = PackageParser.generatePackageInfo(parsed, null,
    510                     PackageManager.GET_PERMISSIONS, 0, 0, null,
    511                     new PackageUserState());
    512             mPkgDigest = parsed.manifestDigest;
    513             as = PackageUtil.getAppSnippet(this, mPkgInfo.applicationInfo, sourceFile);
    514         }
    515         mInstallFlowAnalytics.setPackageInfoObtained();
    516 
    517         //set view
    518         setContentView(R.layout.install_start);
    519         mInstallConfirm = findViewById(R.id.install_confirm_panel);
    520         mInstallConfirm.setVisibility(View.INVISIBLE);
    521         PackageUtil.initSnippetForNewApp(this, as, R.id.app_snippet);
    522 
    523         mOriginatingUid = getOriginatingUid(intent);
    524 
    525         // Block the install attempt on the Unknown Sources setting if necessary.
    526         if ((requestFromUnknownSource) && (!isInstallingUnknownAppsAllowed())) {
    527             //ask user to enable setting first
    528             showDialogInner(DLG_UNKNOWN_APPS);
    529             mInstallFlowAnalytics.setFlowFinished(
    530                     InstallFlowAnalytics.RESULT_BLOCKED_BY_UNKNOWN_SOURCES_SETTING);
    531             return;
    532         }
    533         initiateInstall();
    534     }
    535 
    536     /** Get the ApplicationInfo for the calling package, if available */
    537     private ApplicationInfo getSourceInfo() {
    538         String callingPackage = getCallingPackage();
    539         if (callingPackage != null) {
    540             try {
    541                 return mPm.getApplicationInfo(callingPackage, 0);
    542             } catch (NameNotFoundException ex) {
    543                 // ignore
    544             }
    545         }
    546         return null;
    547     }
    548 
    549 
    550     /** Get the originating uid if possible, or VerificationParams.NO_UID if not available */
    551     private int getOriginatingUid(Intent intent) {
    552         // The originating uid from the intent. We only trust/use this if it comes from a
    553         // system application
    554         int uidFromIntent = intent.getIntExtra(Intent.EXTRA_ORIGINATING_UID,
    555                 VerificationParams.NO_UID);
    556 
    557         // Get the source info from the calling package, if available. This will be the
    558         // definitive calling package, but it only works if the intent was started using
    559         // startActivityForResult,
    560         ApplicationInfo sourceInfo = getSourceInfo();
    561         if (sourceInfo != null) {
    562             if (uidFromIntent != VerificationParams.NO_UID &&
    563                     (mSourceInfo.flags & ApplicationInfo.FLAG_PRIVILEGED) != 0) {
    564                 return uidFromIntent;
    565 
    566             }
    567             // We either didn't get a uid in the intent, or we don't trust it. Use the
    568             // uid of the calling package instead.
    569             return sourceInfo.uid;
    570         }
    571 
    572         // We couldn't get the specific calling package. Let's get the uid instead
    573         int callingUid;
    574         try {
    575             callingUid = ActivityManagerNative.getDefault()
    576                     .getLaunchedFromUid(getActivityToken());
    577         } catch (android.os.RemoteException ex) {
    578             Log.w(TAG, "Could not determine the launching uid.");
    579             // nothing else we can do
    580             return VerificationParams.NO_UID;
    581         }
    582 
    583         // If we got a uid from the intent, we need to verify that the caller is a
    584         // privileged system package before we use it
    585         if (uidFromIntent != VerificationParams.NO_UID) {
    586             String[] callingPackages = mPm.getPackagesForUid(callingUid);
    587             if (callingPackages != null) {
    588                 for (String packageName: callingPackages) {
    589                     try {
    590                         ApplicationInfo applicationInfo =
    591                                 mPm.getApplicationInfo(packageName, 0);
    592 
    593                         if ((applicationInfo.flags & ApplicationInfo.FLAG_PRIVILEGED) != 0) {
    594                             return uidFromIntent;
    595                         }
    596                     } catch (NameNotFoundException ex) {
    597                         // ignore it, and try the next package
    598                     }
    599                 }
    600             }
    601         }
    602         // We either didn't get a uid from the intent, or we don't trust it. Use the
    603         // calling uid instead.
    604         return callingUid;
    605     }
    606 
    607     @Override
    608     public void onBackPressed() {
    609         if (mSessionId != -1) {
    610             mInstaller.setPermissionsResult(mSessionId, false);
    611         }
    612         mInstallFlowAnalytics.setFlowFinished(
    613                 InstallFlowAnalytics.RESULT_CANCELLED_BY_USER);
    614         super.onBackPressed();
    615     }
    616 
    617     // Generic handling when pressing back key
    618     public void onCancel(DialogInterface dialog) {
    619         finish();
    620     }
    621 
    622     public void onClick(View v) {
    623         if(v == mOk) {
    624             if (mOkCanInstall || mScrollView == null) {
    625                 mInstallFlowAnalytics.setInstallButtonClicked();
    626                 if (mSessionId != -1) {
    627                     mInstaller.setPermissionsResult(mSessionId, true);
    628 
    629                     // We're only confirming permissions, so we don't really know how the
    630                     // story ends; assume success.
    631                     mInstallFlowAnalytics.setFlowFinishedWithPackageManagerResult(
    632                             PackageManager.INSTALL_SUCCEEDED);
    633                 } else {
    634                     // Start subactivity to actually install the application
    635                     Intent newIntent = new Intent();
    636                     newIntent.putExtra(PackageUtil.INTENT_ATTR_APPLICATION_INFO,
    637                             mPkgInfo.applicationInfo);
    638                     newIntent.setData(mPackageURI);
    639                     newIntent.setClass(this, InstallAppProgress.class);
    640                     newIntent.putExtra(InstallAppProgress.EXTRA_MANIFEST_DIGEST, mPkgDigest);
    641                     newIntent.putExtra(
    642                             InstallAppProgress.EXTRA_INSTALL_FLOW_ANALYTICS, mInstallFlowAnalytics);
    643                     String installerPackageName = getIntent().getStringExtra(
    644                             Intent.EXTRA_INSTALLER_PACKAGE_NAME);
    645                     if (mOriginatingURI != null) {
    646                         newIntent.putExtra(Intent.EXTRA_ORIGINATING_URI, mOriginatingURI);
    647                     }
    648                     if (mReferrerURI != null) {
    649                         newIntent.putExtra(Intent.EXTRA_REFERRER, mReferrerURI);
    650                     }
    651                     if (mOriginatingUid != VerificationParams.NO_UID) {
    652                         newIntent.putExtra(Intent.EXTRA_ORIGINATING_UID, mOriginatingUid);
    653                     }
    654                     if (installerPackageName != null) {
    655                         newIntent.putExtra(Intent.EXTRA_INSTALLER_PACKAGE_NAME,
    656                                 installerPackageName);
    657                     }
    658                     if (getIntent().getBooleanExtra(Intent.EXTRA_RETURN_RESULT, false)) {
    659                         newIntent.putExtra(Intent.EXTRA_RETURN_RESULT, true);
    660                         newIntent.addFlags(Intent.FLAG_ACTIVITY_FORWARD_RESULT);
    661                     }
    662                     if(localLOGV) Log.i(TAG, "downloaded app uri="+mPackageURI);
    663                     startActivity(newIntent);
    664                 }
    665                 finish();
    666             } else {
    667                 mScrollView.pageScroll(View.FOCUS_DOWN);
    668             }
    669         } else if(v == mCancel) {
    670             // Cancel and finish
    671             setResult(RESULT_CANCELED);
    672             if (mSessionId != -1) {
    673                 mInstaller.setPermissionsResult(mSessionId, false);
    674             }
    675             mInstallFlowAnalytics.setFlowFinished(
    676                     InstallFlowAnalytics.RESULT_CANCELLED_BY_USER);
    677             finish();
    678         }
    679     }
    680 }
    681