• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.Log;
43 import android.view.LayoutInflater;
44 import android.view.View;
45 import android.view.View.OnClickListener;
46 import android.view.ViewGroup;
47 import android.widget.AppSecurityPermissions;
48 import android.widget.Button;
49 import android.widget.TabHost;
50 import android.widget.TextView;
51 
52 import java.io.File;
53 import java.util.List;
54 
55 /*
56  * This activity is launched when a new application is installed via side loading
57  * The package is first parsed and the user is notified of parse errors via a dialog.
58  * If the package is successfully parsed, the user is notified to turn on the install unknown
59  * applications setting. A memory check is made at this point and the user is notified of out
60  * of memory conditions if any. If the package is already existing on the device,
61  * a confirmation dialog (to replace the existing package) is presented to the user.
62  * Based on the user response the package is then installed by launching InstallAppConfirm
63  * sub activity. All state transitions are handled in this activity
64  */
65 public class PackageInstallerActivity extends Activity implements OnCancelListener, OnClickListener {
66     private static final String TAG = "PackageInstaller";
67     private Uri mPackageURI;
68     private Uri mOriginatingURI;
69     private Uri mReferrerURI;
70     private int mOriginatingUid = VerificationParams.NO_UID;
71     private ManifestDigest mPkgDigest;
72 
73     private boolean localLOGV = false;
74     PackageManager mPm;
75     PackageInfo mPkgInfo;
76     ApplicationInfo mSourceInfo;
77 
78     // ApplicationInfo object primarily used for already existing applications
79     private ApplicationInfo mAppInfo = null;
80 
81     private InstallFlowAnalytics mInstallFlowAnalytics;
82 
83     // View for install progress
84     View mInstallConfirm;
85     // Buttons to indicate user acceptance
86     private Button mOk;
87     private Button mCancel;
88     CaffeinatedScrollView mScrollView = null;
89     private boolean mOkCanInstall = false;
90 
91     static final String PREFS_ALLOWED_SOURCES = "allowed_sources";
92 
93     private static final String PACKAGE_MIME_TYPE = "application/vnd.android.package-archive";
94 
95     private static final String TAB_ID_ALL = "all";
96     private static final String TAB_ID_NEW = "new";
97 
98     // Dialog identifiers used in showDialog
99     private static final int DLG_BASE = 0;
100     private static final int DLG_UNKNOWN_APPS = DLG_BASE + 1;
101     private static final int DLG_PACKAGE_ERROR = DLG_BASE + 2;
102     private static final int DLG_OUT_OF_SPACE = DLG_BASE + 3;
103     private static final int DLG_INSTALL_ERROR = DLG_BASE + 4;
104     private static final int DLG_ALLOW_SOURCE = DLG_BASE + 5;
105 
startInstallConfirm()106     private void startInstallConfirm() {
107         TabHost tabHost = (TabHost)findViewById(android.R.id.tabhost);
108         tabHost.setup();
109         ViewPager viewPager = (ViewPager)findViewById(R.id.pager);
110         TabsAdapter adapter = new TabsAdapter(this, tabHost, viewPager);
111         adapter.setOnTabChangedListener(new TabHost.OnTabChangeListener() {
112             @Override
113             public void onTabChanged(String tabId) {
114                 if (TAB_ID_ALL.equals(tabId)) {
115                     mInstallFlowAnalytics.setAllPermissionsDisplayed(true);
116                 } else if (TAB_ID_NEW.equals(tabId)) {
117                     mInstallFlowAnalytics.setNewPermissionsDisplayed(true);
118                 }
119             }
120         });
121 
122         boolean permVisible = false;
123         mScrollView = null;
124         mOkCanInstall = false;
125         int msg = 0;
126         if (mPkgInfo != null) {
127             AppSecurityPermissions perms = new AppSecurityPermissions(this, mPkgInfo);
128             final int NP = perms.getPermissionCount(AppSecurityPermissions.WHICH_PERSONAL);
129             final int ND = perms.getPermissionCount(AppSecurityPermissions.WHICH_DEVICE);
130             if (mAppInfo != null) {
131                 msg = (mAppInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0
132                         ? R.string.install_confirm_question_update_system
133                         : R.string.install_confirm_question_update;
134                 mScrollView = new CaffeinatedScrollView(this);
135                 mScrollView.setFillViewport(true);
136                 boolean newPermissionsFound =
137                         (perms.getPermissionCount(AppSecurityPermissions.WHICH_NEW) > 0);
138                 mInstallFlowAnalytics.setNewPermissionsFound(newPermissionsFound);
139                 if (newPermissionsFound) {
140                     permVisible = true;
141                     mScrollView.addView(perms.getPermissionsView(
142                             AppSecurityPermissions.WHICH_NEW));
143                 } else {
144                     LayoutInflater inflater = (LayoutInflater)getSystemService(
145                             Context.LAYOUT_INFLATER_SERVICE);
146                     TextView label = (TextView)inflater.inflate(R.layout.label, null);
147                     label.setText(R.string.no_new_perms);
148                     mScrollView.addView(label);
149                 }
150                 adapter.addTab(tabHost.newTabSpec(TAB_ID_NEW).setIndicator(
151                         getText(R.string.newPerms)), mScrollView);
152             } else  {
153                 findViewById(R.id.tabscontainer).setVisibility(View.GONE);
154                 findViewById(R.id.divider).setVisibility(View.VISIBLE);
155             }
156             if (NP > 0 || ND > 0) {
157                 permVisible = true;
158                 LayoutInflater inflater = (LayoutInflater)getSystemService(
159                         Context.LAYOUT_INFLATER_SERVICE);
160                 View root = inflater.inflate(R.layout.permissions_list, null);
161                 if (mScrollView == null) {
162                     mScrollView = (CaffeinatedScrollView)root.findViewById(R.id.scrollview);
163                 }
164                 if (NP > 0) {
165                     ((ViewGroup)root.findViewById(R.id.privacylist)).addView(
166                             perms.getPermissionsView(AppSecurityPermissions.WHICH_PERSONAL));
167                 } else {
168                     root.findViewById(R.id.privacylist).setVisibility(View.GONE);
169                 }
170                 if (ND > 0) {
171                     ((ViewGroup)root.findViewById(R.id.devicelist)).addView(
172                             perms.getPermissionsView(AppSecurityPermissions.WHICH_DEVICE));
173                 } else {
174                     root.findViewById(R.id.devicelist).setVisibility(View.GONE);
175                 }
176                 adapter.addTab(tabHost.newTabSpec(TAB_ID_ALL).setIndicator(
177                         getText(R.string.allPerms)), root);
178             }
179         }
180         mInstallFlowAnalytics.setPermissionsDisplayed(permVisible);
181         if (!permVisible) {
182             if (mAppInfo != null) {
183                 // This is an update to an application, but there are no
184                 // permissions at all.
185                 msg = (mAppInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0
186                         ? R.string.install_confirm_question_update_system_no_perms
187                         : R.string.install_confirm_question_update_no_perms;
188             } else {
189                 // This is a new application with no permissions.
190                 msg = R.string.install_confirm_question_no_perms;
191             }
192             tabHost.setVisibility(View.GONE);
193             mInstallFlowAnalytics.setAllPermissionsDisplayed(false);
194             mInstallFlowAnalytics.setNewPermissionsDisplayed(false);
195             findViewById(R.id.filler).setVisibility(View.VISIBLE);
196             findViewById(R.id.divider).setVisibility(View.GONE);
197             mScrollView = null;
198         }
199         if (msg != 0) {
200             ((TextView)findViewById(R.id.install_confirm_question)).setText(msg);
201         }
202         mInstallConfirm.setVisibility(View.VISIBLE);
203         mOk = (Button)findViewById(R.id.ok_button);
204         mCancel = (Button)findViewById(R.id.cancel_button);
205         mOk.setOnClickListener(this);
206         mCancel.setOnClickListener(this);
207         if (mScrollView == null) {
208             // There is nothing to scroll view, so the ok button is immediately
209             // set to install.
210             mOk.setText(R.string.install);
211             mOkCanInstall = true;
212         } else {
213             mScrollView.setFullScrollAction(new Runnable() {
214                 @Override
215                 public void run() {
216                     mOk.setText(R.string.install);
217                     mOkCanInstall = true;
218                 }
219             });
220         }
221     }
222 
showDialogInner(int id)223     private void showDialogInner(int id) {
224         // TODO better fix for this? Remove dialog so that it gets created again
225         removeDialog(id);
226         showDialog(id);
227     }
228 
229     @Override
onCreateDialog(int id, Bundle bundle)230     public Dialog onCreateDialog(int id, Bundle bundle) {
231         switch (id) {
232         case DLG_UNKNOWN_APPS:
233             return new AlertDialog.Builder(this)
234                     .setTitle(R.string.unknown_apps_dlg_title)
235                     .setMessage(R.string.unknown_apps_dlg_text)
236                     .setNegativeButton(R.string.cancel, new DialogInterface.OnClickListener() {
237                         public void onClick(DialogInterface dialog, int which) {
238                             Log.i(TAG, "Finishing off activity so that user can navigate to settings manually");
239                             finish();
240                         }})
241                     .setPositiveButton(R.string.settings, new DialogInterface.OnClickListener() {
242                         public void onClick(DialogInterface dialog, int which) {
243                             Log.i(TAG, "Launching settings");
244                             launchSettingsAppAndFinish();
245                         }
246                     })
247                     .setOnCancelListener(this)
248                     .create();
249         case DLG_PACKAGE_ERROR :
250             return new AlertDialog.Builder(this)
251                     .setTitle(R.string.Parse_error_dlg_title)
252                     .setMessage(R.string.Parse_error_dlg_text)
253                     .setPositiveButton(R.string.ok, new DialogInterface.OnClickListener() {
254                         public void onClick(DialogInterface dialog, int which) {
255                             finish();
256                         }
257                     })
258                     .setOnCancelListener(this)
259                     .create();
260         case DLG_OUT_OF_SPACE:
261             // Guaranteed not to be null. will default to package name if not set by app
262             CharSequence appTitle = mPm.getApplicationLabel(mPkgInfo.applicationInfo);
263             String dlgText = getString(R.string.out_of_space_dlg_text,
264                     appTitle.toString());
265             return new AlertDialog.Builder(this)
266                     .setTitle(R.string.out_of_space_dlg_title)
267                     .setMessage(dlgText)
268                     .setPositiveButton(R.string.manage_applications, new DialogInterface.OnClickListener() {
269                         public void onClick(DialogInterface dialog, int which) {
270                             //launch manage applications
271                             Intent intent = new Intent("android.intent.action.MANAGE_PACKAGE_STORAGE");
272                             intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
273                             startActivity(intent);
274                             finish();
275                         }
276                     })
277                     .setNegativeButton(R.string.cancel, new DialogInterface.OnClickListener() {
278                         public void onClick(DialogInterface dialog, int which) {
279                             Log.i(TAG, "Canceling installation");
280                             finish();
281                         }
282                   })
283                   .setOnCancelListener(this)
284                   .create();
285         case DLG_INSTALL_ERROR :
286             // Guaranteed not to be null. will default to package name if not set by app
287             CharSequence appTitle1 = mPm.getApplicationLabel(mPkgInfo.applicationInfo);
288             String dlgText1 = getString(R.string.install_failed_msg,
289                     appTitle1.toString());
290             return new AlertDialog.Builder(this)
291                     .setTitle(R.string.install_failed)
292                     .setNeutralButton(R.string.ok, new DialogInterface.OnClickListener() {
293                         public void onClick(DialogInterface dialog, int which) {
294                             finish();
295                         }
296                     })
297                     .setMessage(dlgText1)
298                     .setOnCancelListener(this)
299                     .create();
300         case DLG_ALLOW_SOURCE:
301             CharSequence appTitle2 = mPm.getApplicationLabel(mSourceInfo);
302             String dlgText2 = getString(R.string.allow_source_dlg_text,
303                     appTitle2.toString());
304             return new AlertDialog.Builder(this)
305                     .setTitle(R.string.allow_source_dlg_title)
306                     .setMessage(dlgText2)
307                     .setNegativeButton(R.string.cancel, new DialogInterface.OnClickListener() {
308                         public void onClick(DialogInterface dialog, int which) {
309                             setResult(RESULT_CANCELED);
310                             finish();
311                         }})
312                     .setPositiveButton(R.string.ok, new DialogInterface.OnClickListener() {
313                         public void onClick(DialogInterface dialog, int which) {
314                             SharedPreferences prefs = getSharedPreferences(PREFS_ALLOWED_SOURCES,
315                                     Context.MODE_PRIVATE);
316                             prefs.edit().putBoolean(mSourceInfo.packageName, true).apply();
317                             startInstallConfirm();
318                         }
319                     })
320                     .setOnCancelListener(this)
321                     .create();
322        }
323        return null;
324    }
325 
326     private void launchSettingsAppAndFinish() {
327         // Create an intent to launch SettingsTwo activity
328         Intent launchSettingsIntent = new Intent(Settings.ACTION_SECURITY_SETTINGS);
329         launchSettingsIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
330         startActivity(launchSettingsIntent);
331         finish();
332     }
333 
334     private boolean isInstallingUnknownAppsAllowed() {
335         return Settings.Global.getInt(getContentResolver(),
336             Settings.Global.INSTALL_NON_MARKET_APPS, 0) > 0;
337     }
338 
339     private boolean isInstallRequestFromUnknownSource(Intent intent) {
340         String callerPackage = getCallingPackage();
341         if (callerPackage != null && intent.getBooleanExtra(
342                 Intent.EXTRA_NOT_UNKNOWN_SOURCE, false)) {
343             try {
344                 mSourceInfo = mPm.getApplicationInfo(callerPackage, 0);
345                 if (mSourceInfo != null) {
346                     if ((mSourceInfo.flags & ApplicationInfo.FLAG_PRIVILEGED) != 0) {
347                         // Privileged apps are not considered an unknown source.
348                         return false;
349                     }
350                 }
351             } catch (NameNotFoundException e) {
352             }
353         }
354 
355         return true;
356     }
357 
358     private boolean isVerifyAppsEnabled() {
359         return Settings.Global.getInt(getContentResolver(),
360                 Settings.Global.PACKAGE_VERIFIER_ENABLE, 1) > 0;
361     }
362 
363     private boolean isAppVerifierInstalled() {
364         final PackageManager pm = getPackageManager();
365         final Intent verification = new Intent(Intent.ACTION_PACKAGE_NEEDS_VERIFICATION);
366         verification.setType(PACKAGE_MIME_TYPE);
367         verification.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
368         final List<ResolveInfo> receivers = pm.queryBroadcastReceivers(verification, 0);
369         return (receivers.size() > 0) ? true : false;
370     }
371 
372     private void initiateInstall() {
373         String pkgName = mPkgInfo.packageName;
374         // Check if there is already a package on the device with this name
375         // but it has been renamed to something else.
376         String[] oldName = mPm.canonicalToCurrentPackageNames(new String[] { pkgName });
377         if (oldName != null && oldName.length > 0 && oldName[0] != null) {
378             pkgName = oldName[0];
379             mPkgInfo.packageName = pkgName;
380             mPkgInfo.applicationInfo.packageName = pkgName;
381         }
382         // Check if package is already installed. display confirmation dialog if replacing pkg
383         try {
384             // This is a little convoluted because we want to get all uninstalled
385             // apps, but this may include apps with just data, and if it is just
386             // data we still want to count it as "installed".
387             mAppInfo = mPm.getApplicationInfo(pkgName,
388                     PackageManager.GET_UNINSTALLED_PACKAGES);
389             if ((mAppInfo.flags&ApplicationInfo.FLAG_INSTALLED) == 0) {
390                 mAppInfo = null;
391             }
392         } catch (NameNotFoundException e) {
393             mAppInfo = null;
394         }
395 
396         mInstallFlowAnalytics.setReplace(mAppInfo != null);
397         mInstallFlowAnalytics.setSystemApp(
398                 (mAppInfo != null) && ((mAppInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0));
399 
400         startInstallConfirm();
401     }
402 
403     void setPmResult(int pmResult) {
404         Intent result = new Intent();
405         result.putExtra(Intent.EXTRA_INSTALL_RESULT, pmResult);
406         setResult(pmResult == PackageManager.INSTALL_SUCCEEDED
407                 ? RESULT_OK : RESULT_FIRST_USER, result);
408     }
409 
410     @Override
411     protected void onCreate(Bundle icicle) {
412         super.onCreate(icicle);
413 
414         // get intent information
415         final Intent intent = getIntent();
416         mPackageURI = intent.getData();
417         mOriginatingURI = intent.getParcelableExtra(Intent.EXTRA_ORIGINATING_URI);
418         mReferrerURI = intent.getParcelableExtra(Intent.EXTRA_REFERRER);
419         mPm = getPackageManager();
420 
421         boolean requestFromUnknownSource = isInstallRequestFromUnknownSource(intent);
422         mInstallFlowAnalytics = new InstallFlowAnalytics();
423         mInstallFlowAnalytics.setContext(this);
424         mInstallFlowAnalytics.setStartTimestampMillis(SystemClock.elapsedRealtime());
425         mInstallFlowAnalytics.setInstallsFromUnknownSourcesPermitted(
426                 isInstallingUnknownAppsAllowed());
427         mInstallFlowAnalytics.setInstallRequestFromUnknownSource(requestFromUnknownSource);
428         mInstallFlowAnalytics.setVerifyAppsEnabled(isVerifyAppsEnabled());
429         mInstallFlowAnalytics.setAppVerifierInstalled(isAppVerifierInstalled());
430         mInstallFlowAnalytics.setPackageUri(mPackageURI.toString());
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