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