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.PackageInfo; 30 import android.content.pm.PackageManager; 31 import android.content.pm.PackageUserState; 32 import android.content.pm.PackageManager.NameNotFoundException; 33 import android.content.pm.PackageParser; 34 import android.content.pm.VerificationParams; 35 import android.graphics.Rect; 36 import android.net.Uri; 37 import android.os.Bundle; 38 import android.provider.Settings; 39 import android.support.v4.view.PagerAdapter; 40 import android.support.v4.view.ViewPager; 41 import android.util.Log; 42 import android.view.LayoutInflater; 43 import android.view.View; 44 import android.view.View.OnClickListener; 45 import android.view.ViewGroup; 46 import android.widget.AppSecurityPermissions; 47 import android.widget.Button; 48 import android.widget.ScrollView; 49 import android.widget.TabHost; 50 import android.widget.TabWidget; 51 import android.widget.TextView; 52 53 import java.io.File; 54 import java.util.ArrayList; 55 56 /* 57 * This activity is launched when a new application is installed via side loading 58 * The package is first parsed and the user is notified of parse errors via a dialog. 59 * If the package is successfully parsed, the user is notified to turn on the install unknown 60 * applications setting. A memory check is made at this point and the user is notified of out 61 * of memory conditions if any. If the package is already existing on the device, 62 * a confirmation dialog (to replace the existing package) is presented to the user. 63 * Based on the user response the package is then installed by launching InstallAppConfirm 64 * sub activity. All state transitions are handled in this activity 65 */ 66 public class PackageInstallerActivity extends Activity implements OnCancelListener, OnClickListener { 67 private static final String TAG = "PackageInstaller"; 68 private Uri mPackageURI; 69 private Uri mOriginatingURI; 70 private Uri mReferrerURI; 71 private int mOriginatingUid = VerificationParams.NO_UID; 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 // View for install progress 82 View mInstallConfirm; 83 // Buttons to indicate user acceptance 84 private Button mOk; 85 private Button mCancel; 86 CaffeinatedScrollView mScrollView = null; 87 private boolean mOkCanInstall = false; 88 89 static final String PREFS_ALLOWED_SOURCES = "allowed_sources"; 90 91 // Dialog identifiers used in showDialog 92 private static final int DLG_BASE = 0; 93 private static final int DLG_UNKNOWN_APPS = DLG_BASE + 1; 94 private static final int DLG_PACKAGE_ERROR = DLG_BASE + 2; 95 private static final int DLG_OUT_OF_SPACE = DLG_BASE + 3; 96 private static final int DLG_INSTALL_ERROR = DLG_BASE + 4; 97 private static final int DLG_ALLOW_SOURCE = DLG_BASE + 5; 98 99 /** 100 * This is a helper class that implements the management of tabs and all 101 * details of connecting a ViewPager with associated TabHost. It relies on a 102 * trick. Normally a tab host has a simple API for supplying a View or 103 * Intent that each tab will show. This is not sufficient for switching 104 * between pages. So instead we make the content part of the tab host 105 * 0dp high (it is not shown) and the TabsAdapter supplies its own dummy 106 * view to show as the tab content. It listens to changes in tabs, and takes 107 * care of switch to the correct paged in the ViewPager whenever the selected 108 * tab changes. 109 */ 110 public static class TabsAdapter extends PagerAdapter 111 implements TabHost.OnTabChangeListener, ViewPager.OnPageChangeListener { 112 private final Context mContext; 113 private final TabHost mTabHost; 114 private final ViewPager mViewPager; 115 private final ArrayList<TabInfo> mTabs = new ArrayList<TabInfo>(); 116 private final Rect mTempRect = new Rect(); 117 118 static final class TabInfo { 119 private final String tag; 120 private final View view; 121 122 TabInfo(String _tag, View _view) { 123 tag = _tag; 124 view = _view; 125 } 126 } 127 128 static class DummyTabFactory implements TabHost.TabContentFactory { 129 private final Context mContext; 130 131 public DummyTabFactory(Context context) { 132 mContext = context; 133 } 134 135 @Override 136 public View createTabContent(String tag) { 137 View v = new View(mContext); 138 v.setMinimumWidth(0); 139 v.setMinimumHeight(0); 140 return v; 141 } 142 } 143 144 public TabsAdapter(Activity activity, TabHost tabHost, ViewPager pager) { 145 mContext = activity; 146 mTabHost = tabHost; 147 mViewPager = pager; 148 mTabHost.setOnTabChangedListener(this); 149 mViewPager.setAdapter(this); 150 mViewPager.setOnPageChangeListener(this); 151 } 152 153 public void addTab(TabHost.TabSpec tabSpec, View view) { 154 tabSpec.setContent(new DummyTabFactory(mContext)); 155 String tag = tabSpec.getTag(); 156 157 TabInfo info = new TabInfo(tag, view); 158 mTabs.add(info); 159 mTabHost.addTab(tabSpec); 160 notifyDataSetChanged(); 161 } 162 163 @Override 164 public int getCount() { 165 return mTabs.size(); 166 } 167 168 @Override 169 public Object instantiateItem(ViewGroup container, int position) { 170 View view = mTabs.get(position).view; 171 container.addView(view); 172 return view; 173 } 174 175 @Override 176 public void destroyItem(ViewGroup container, int position, Object object) { 177 container.removeView((View)object); 178 } 179 180 @Override 181 public boolean isViewFromObject(View view, Object object) { 182 return view == object; 183 } 184 185 @Override 186 public void onTabChanged(String tabId) { 187 int position = mTabHost.getCurrentTab(); 188 mViewPager.setCurrentItem(position); 189 } 190 191 @Override 192 public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) { 193 } 194 195 @Override 196 public void onPageSelected(int position) { 197 // Unfortunately when TabHost changes the current tab, it kindly 198 // also takes care of putting focus on it when not in touch mode. 199 // The jerk. 200 // This hack tries to prevent this from pulling focus out of our 201 // ViewPager. 202 TabWidget widget = mTabHost.getTabWidget(); 203 int oldFocusability = widget.getDescendantFocusability(); 204 widget.setDescendantFocusability(ViewGroup.FOCUS_BLOCK_DESCENDANTS); 205 mTabHost.setCurrentTab(position); 206 widget.setDescendantFocusability(oldFocusability); 207 208 // Scroll the current tab into visibility if needed. 209 View tab = widget.getChildTabViewAt(position); 210 mTempRect.set(tab.getLeft(), tab.getTop(), tab.getRight(), tab.getBottom()); 211 widget.requestRectangleOnScreen(mTempRect, false); 212 213 // Make sure the scrollbars are visible for a moment after selection 214 final View contentView = mTabs.get(position).view; 215 if (contentView instanceof CaffeinatedScrollView) { 216 ((CaffeinatedScrollView) contentView).awakenScrollBars(); 217 } 218 } 219 220 @Override 221 public void onPageScrollStateChanged(int state) { 222 } 223 } 224 225 private void startInstallConfirm() { 226 TabHost tabHost = (TabHost)findViewById(android.R.id.tabhost); 227 tabHost.setup(); 228 ViewPager viewPager = (ViewPager)findViewById(R.id.pager); 229 TabsAdapter adapter = new TabsAdapter(this, tabHost, viewPager); 230 231 boolean permVisible = false; 232 mScrollView = null; 233 mOkCanInstall = false; 234 int msg = 0; 235 if (mPkgInfo != null) { 236 AppSecurityPermissions perms = new AppSecurityPermissions(this, mPkgInfo); 237 final int NP = perms.getPermissionCount(AppSecurityPermissions.WHICH_PERSONAL); 238 final int ND = perms.getPermissionCount(AppSecurityPermissions.WHICH_DEVICE); 239 if (mAppInfo != null) { 240 msg = (mAppInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0 241 ? R.string.install_confirm_question_update_system 242 : R.string.install_confirm_question_update; 243 mScrollView = new CaffeinatedScrollView(this); 244 mScrollView.setFillViewport(true); 245 if (perms.getPermissionCount(AppSecurityPermissions.WHICH_NEW) > 0) { 246 permVisible = true; 247 mScrollView.addView(perms.getPermissionsView( 248 AppSecurityPermissions.WHICH_NEW)); 249 } else { 250 LayoutInflater inflater = (LayoutInflater)getSystemService( 251 Context.LAYOUT_INFLATER_SERVICE); 252 TextView label = (TextView)inflater.inflate(R.layout.label, null); 253 label.setText(R.string.no_new_perms); 254 mScrollView.addView(label); 255 } 256 adapter.addTab(tabHost.newTabSpec("new").setIndicator( 257 getText(R.string.newPerms)), mScrollView); 258 } else { 259 findViewById(R.id.tabscontainer).setVisibility(View.GONE); 260 findViewById(R.id.divider).setVisibility(View.VISIBLE); 261 } 262 if (NP > 0 || ND > 0) { 263 permVisible = true; 264 LayoutInflater inflater = (LayoutInflater)getSystemService( 265 Context.LAYOUT_INFLATER_SERVICE); 266 View root = inflater.inflate(R.layout.permissions_list, null); 267 if (mScrollView == null) { 268 mScrollView = (CaffeinatedScrollView)root.findViewById(R.id.scrollview); 269 } 270 if (NP > 0) { 271 ((ViewGroup)root.findViewById(R.id.privacylist)).addView( 272 perms.getPermissionsView(AppSecurityPermissions.WHICH_PERSONAL)); 273 } else { 274 root.findViewById(R.id.privacylist).setVisibility(View.GONE); 275 } 276 if (ND > 0) { 277 ((ViewGroup)root.findViewById(R.id.devicelist)).addView( 278 perms.getPermissionsView(AppSecurityPermissions.WHICH_DEVICE)); 279 } else { 280 root.findViewById(R.id.devicelist).setVisibility(View.GONE); 281 } 282 adapter.addTab(tabHost.newTabSpec("all").setIndicator( 283 getText(R.string.allPerms)), root); 284 } 285 } 286 if (!permVisible) { 287 if (mAppInfo != null) { 288 // This is an update to an application, but there are no 289 // permissions at all. 290 msg = (mAppInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0 291 ? R.string.install_confirm_question_update_system_no_perms 292 : R.string.install_confirm_question_update_no_perms; 293 } else { 294 // This is a new application with no permissions. 295 msg = R.string.install_confirm_question_no_perms; 296 } 297 tabHost.setVisibility(View.GONE); 298 findViewById(R.id.filler).setVisibility(View.VISIBLE); 299 findViewById(R.id.divider).setVisibility(View.GONE); 300 mScrollView = null; 301 } 302 if (msg != 0) { 303 ((TextView)findViewById(R.id.install_confirm_question)).setText(msg); 304 } 305 mInstallConfirm.setVisibility(View.VISIBLE); 306 mOk = (Button)findViewById(R.id.ok_button); 307 mCancel = (Button)findViewById(R.id.cancel_button); 308 mOk.setOnClickListener(this); 309 mCancel.setOnClickListener(this); 310 if (mScrollView == null) { 311 // There is nothing to scroll view, so the ok button is immediately 312 // set to install. 313 mOk.setText(R.string.install); 314 mOkCanInstall = true; 315 } else { 316 mScrollView.setFullScrollAction(new Runnable() { 317 @Override 318 public void run() { 319 mOk.setText(R.string.install); 320 mOkCanInstall = true; 321 } 322 }); 323 } 324 } 325 326 private void showDialogInner(int id) { 327 // TODO better fix for this? Remove dialog so that it gets created again 328 removeDialog(id); 329 showDialog(id); 330 } 331 332 @Override 333 public Dialog onCreateDialog(int id, Bundle bundle) { 334 switch (id) { 335 case DLG_UNKNOWN_APPS: 336 return new AlertDialog.Builder(this) 337 .setTitle(R.string.unknown_apps_dlg_title) 338 .setMessage(R.string.unknown_apps_dlg_text) 339 .setNegativeButton(R.string.cancel, new DialogInterface.OnClickListener() { 340 public void onClick(DialogInterface dialog, int which) { 341 Log.i(TAG, "Finishing off activity so that user can navigate to settings manually"); 342 finish(); 343 }}) 344 .setPositiveButton(R.string.settings, new DialogInterface.OnClickListener() { 345 public void onClick(DialogInterface dialog, int which) { 346 Log.i(TAG, "Launching settings"); 347 launchSettingsAppAndFinish(); 348 } 349 }) 350 .setOnCancelListener(this) 351 .create(); 352 case DLG_PACKAGE_ERROR : 353 return new AlertDialog.Builder(this) 354 .setTitle(R.string.Parse_error_dlg_title) 355 .setMessage(R.string.Parse_error_dlg_text) 356 .setPositiveButton(R.string.ok, new DialogInterface.OnClickListener() { 357 public void onClick(DialogInterface dialog, int which) { 358 finish(); 359 } 360 }) 361 .setOnCancelListener(this) 362 .create(); 363 case DLG_OUT_OF_SPACE: 364 // Guaranteed not to be null. will default to package name if not set by app 365 CharSequence appTitle = mPm.getApplicationLabel(mPkgInfo.applicationInfo); 366 String dlgText = getString(R.string.out_of_space_dlg_text, 367 appTitle.toString()); 368 return new AlertDialog.Builder(this) 369 .setTitle(R.string.out_of_space_dlg_title) 370 .setMessage(dlgText) 371 .setPositiveButton(R.string.manage_applications, new DialogInterface.OnClickListener() { 372 public void onClick(DialogInterface dialog, int which) { 373 //launch manage applications 374 Intent intent = new Intent("android.intent.action.MANAGE_PACKAGE_STORAGE"); 375 intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); 376 startActivity(intent); 377 finish(); 378 } 379 }) 380 .setNegativeButton(R.string.cancel, new DialogInterface.OnClickListener() { 381 public void onClick(DialogInterface dialog, int which) { 382 Log.i(TAG, "Canceling installation"); 383 finish(); 384 } 385 }) 386 .setOnCancelListener(this) 387 .create(); 388 case DLG_INSTALL_ERROR : 389 // Guaranteed not to be null. will default to package name if not set by app 390 CharSequence appTitle1 = mPm.getApplicationLabel(mPkgInfo.applicationInfo); 391 String dlgText1 = getString(R.string.install_failed_msg, 392 appTitle1.toString()); 393 return new AlertDialog.Builder(this) 394 .setTitle(R.string.install_failed) 395 .setNeutralButton(R.string.ok, new DialogInterface.OnClickListener() { 396 public void onClick(DialogInterface dialog, int which) { 397 finish(); 398 } 399 }) 400 .setMessage(dlgText1) 401 .setOnCancelListener(this) 402 .create(); 403 case DLG_ALLOW_SOURCE: 404 CharSequence appTitle2 = mPm.getApplicationLabel(mSourceInfo); 405 String dlgText2 = getString(R.string.allow_source_dlg_text, 406 appTitle2.toString()); 407 return new AlertDialog.Builder(this) 408 .setTitle(R.string.allow_source_dlg_title) 409 .setMessage(dlgText2) 410 .setNegativeButton(R.string.cancel, new DialogInterface.OnClickListener() { 411 public void onClick(DialogInterface dialog, int which) { 412 setResult(RESULT_CANCELED); 413 finish(); 414 }}) 415 .setPositiveButton(R.string.ok, new DialogInterface.OnClickListener() { 416 public void onClick(DialogInterface dialog, int which) { 417 SharedPreferences prefs = getSharedPreferences(PREFS_ALLOWED_SOURCES, 418 Context.MODE_PRIVATE); 419 prefs.edit().putBoolean(mSourceInfo.packageName, true).apply(); 420 startInstallConfirm(); 421 } 422 }) 423 .setOnCancelListener(this) 424 .create(); 425 } 426 return null; 427 } 428 429 private void launchSettingsAppAndFinish() { 430 // Create an intent to launch SettingsTwo activity 431 Intent launchSettingsIntent = new Intent(Settings.ACTION_SECURITY_SETTINGS); 432 launchSettingsIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); 433 startActivity(launchSettingsIntent); 434 finish(); 435 } 436 437 private boolean isInstallingUnknownAppsAllowed() { 438 return Settings.Global.getInt(getContentResolver(), 439 Settings.Global.INSTALL_NON_MARKET_APPS, 0) > 0; 440 } 441 442 private void initiateInstall() { 443 String pkgName = mPkgInfo.packageName; 444 // Check if there is already a package on the device with this name 445 // but it has been renamed to something else. 446 String[] oldName = mPm.canonicalToCurrentPackageNames(new String[] { pkgName }); 447 if (oldName != null && oldName.length > 0 && oldName[0] != null) { 448 pkgName = oldName[0]; 449 mPkgInfo.packageName = pkgName; 450 mPkgInfo.applicationInfo.packageName = pkgName; 451 } 452 // Check if package is already installed. display confirmation dialog if replacing pkg 453 try { 454 // This is a little convoluted because we want to get all uninstalled 455 // apps, but this may include apps with just data, and if it is just 456 // data we still want to count it as "installed". 457 mAppInfo = mPm.getApplicationInfo(pkgName, 458 PackageManager.GET_UNINSTALLED_PACKAGES); 459 if ((mAppInfo.flags&ApplicationInfo.FLAG_INSTALLED) == 0) { 460 mAppInfo = null; 461 } 462 } catch (NameNotFoundException e) { 463 mAppInfo = null; 464 } 465 startInstallConfirm(); 466 } 467 468 void setPmResult(int pmResult) { 469 Intent result = new Intent(); 470 result.putExtra(Intent.EXTRA_INSTALL_RESULT, pmResult); 471 setResult(pmResult == PackageManager.INSTALL_SUCCEEDED 472 ? RESULT_OK : RESULT_FIRST_USER, result); 473 } 474 475 @Override 476 protected void onCreate(Bundle icicle) { 477 super.onCreate(icicle); 478 479 // get intent information 480 final Intent intent = getIntent(); 481 mPackageURI = intent.getData(); 482 mOriginatingURI = intent.getParcelableExtra(Intent.EXTRA_ORIGINATING_URI); 483 mReferrerURI = intent.getParcelableExtra(Intent.EXTRA_REFERRER); 484 mPm = getPackageManager(); 485 486 final String scheme = mPackageURI.getScheme(); 487 if (scheme != null && !"file".equals(scheme) && !"package".equals(scheme)) { 488 Log.w(TAG, "Unsupported scheme " + scheme); 489 setPmResult(PackageManager.INSTALL_FAILED_INVALID_URI); 490 return; 491 } 492 493 final PackageUtil.AppSnippet as; 494 if ("package".equals(mPackageURI.getScheme())) { 495 try { 496 mPkgInfo = mPm.getPackageInfo(mPackageURI.getSchemeSpecificPart(), 497 PackageManager.GET_PERMISSIONS | PackageManager.GET_UNINSTALLED_PACKAGES); 498 } catch (NameNotFoundException e) { 499 } 500 if (mPkgInfo == null) { 501 Log.w(TAG, "Requested package " + mPackageURI.getScheme() 502 + " not available. Discontinuing installation"); 503 showDialogInner(DLG_PACKAGE_ERROR); 504 setPmResult(PackageManager.INSTALL_FAILED_INVALID_APK); 505 return; 506 } 507 as = new PackageUtil.AppSnippet(mPm.getApplicationLabel(mPkgInfo.applicationInfo), 508 mPm.getApplicationIcon(mPkgInfo.applicationInfo)); 509 } else { 510 final File sourceFile = new File(mPackageURI.getPath()); 511 PackageParser.Package parsed = PackageUtil.getPackageInfo(sourceFile); 512 513 // Check for parse errors 514 if (parsed == null) { 515 Log.w(TAG, "Parse error when parsing manifest. Discontinuing installation"); 516 showDialogInner(DLG_PACKAGE_ERROR); 517 setPmResult(PackageManager.INSTALL_FAILED_INVALID_APK); 518 return; 519 } 520 mPkgInfo = PackageParser.generatePackageInfo(parsed, null, 521 PackageManager.GET_PERMISSIONS, 0, 0, null, 522 new PackageUserState()); 523 as = PackageUtil.getAppSnippet(this, mPkgInfo.applicationInfo, sourceFile); 524 } 525 526 //set view 527 setContentView(R.layout.install_start); 528 mInstallConfirm = findViewById(R.id.install_confirm_panel); 529 mInstallConfirm.setVisibility(View.INVISIBLE); 530 PackageUtil.initSnippetForNewApp(this, as, R.id.app_snippet); 531 532 mOriginatingUid = getOriginatingUid(intent); 533 534 // Deal with install source. 535 String callerPackage = getCallingPackage(); 536 if (callerPackage != null && intent.getBooleanExtra( 537 Intent.EXTRA_NOT_UNKNOWN_SOURCE, false)) { 538 try { 539 mSourceInfo = mPm.getApplicationInfo(callerPackage, 0); 540 if (mSourceInfo != null) { 541 if ((mSourceInfo.flags&ApplicationInfo.FLAG_SYSTEM) != 0) { 542 // System apps don't need to be approved. 543 initiateInstall(); 544 return; 545 } 546 /* for now this is disabled, since the user would need to 547 * have enabled the global "unknown sources" setting in the 548 * first place in order to get here. 549 SharedPreferences prefs = getSharedPreferences(PREFS_ALLOWED_SOURCES, 550 Context.MODE_PRIVATE); 551 if (prefs.getBoolean(mSourceInfo.packageName, false)) { 552 // User has already allowed this one. 553 initiateInstall(); 554 return; 555 } 556 //ask user to enable setting first 557 showDialogInner(DLG_ALLOW_SOURCE); 558 return; 559 */ 560 } 561 } catch (NameNotFoundException e) { 562 } 563 } 564 565 // Check unknown sources. 566 if (!isInstallingUnknownAppsAllowed()) { 567 //ask user to enable setting first 568 showDialogInner(DLG_UNKNOWN_APPS); 569 return; 570 } 571 initiateInstall(); 572 } 573 574 /** Get the ApplicationInfo for the calling package, if available */ 575 private ApplicationInfo getSourceInfo() { 576 String callingPackage = getCallingPackage(); 577 if (callingPackage != null) { 578 try { 579 return mPm.getApplicationInfo(callingPackage, 0); 580 } catch (NameNotFoundException ex) { 581 // ignore 582 } 583 } 584 return null; 585 } 586 587 588 /** Get the originating uid if possible, or VerificationParams.NO_UID if not available */ 589 private int getOriginatingUid(Intent intent) { 590 // The originating uid from the intent. We only trust/use this if it comes from a 591 // system application 592 int uidFromIntent = intent.getIntExtra(Intent.EXTRA_ORIGINATING_UID, 593 VerificationParams.NO_UID); 594 595 // Get the source info from the calling package, if available. This will be the 596 // definitive calling package, but it only works if the intent was started using 597 // startActivityForResult, 598 ApplicationInfo sourceInfo = getSourceInfo(); 599 if (sourceInfo != null) { 600 if (uidFromIntent != VerificationParams.NO_UID && 601 (mSourceInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0) { 602 return uidFromIntent; 603 604 } 605 // We either didn't get a uid in the intent, or we don't trust it. Use the 606 // uid of the calling package instead. 607 return sourceInfo.uid; 608 } 609 610 // We couldn't get the specific calling package. Let's get the uid instead 611 int callingUid; 612 try { 613 callingUid = ActivityManagerNative.getDefault() 614 .getLaunchedFromUid(getActivityToken()); 615 } catch (android.os.RemoteException ex) { 616 Log.w(TAG, "Could not determine the launching uid."); 617 // nothing else we can do 618 return VerificationParams.NO_UID; 619 } 620 621 // If we got a uid from the intent, we need to verify that the caller is a 622 // system package before we use it 623 if (uidFromIntent != VerificationParams.NO_UID) { 624 String[] callingPackages = mPm.getPackagesForUid(callingUid); 625 if (callingPackages != null) { 626 for (String packageName: callingPackages) { 627 try { 628 ApplicationInfo applicationInfo = 629 mPm.getApplicationInfo(packageName, 0); 630 631 if ((applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0) { 632 return uidFromIntent; 633 } 634 } catch (NameNotFoundException ex) { 635 // ignore it, and try the next package 636 } 637 } 638 } 639 } 640 // We either didn't get a uid from the intent, or we don't trust it. Use the 641 // calling uid instead. 642 return callingUid; 643 } 644 645 // Generic handling when pressing back key 646 public void onCancel(DialogInterface dialog) { 647 finish(); 648 } 649 650 public void onClick(View v) { 651 if(v == mOk) { 652 if (mOkCanInstall || mScrollView == null) { 653 // Start subactivity to actually install the application 654 Intent newIntent = new Intent(); 655 newIntent.putExtra(PackageUtil.INTENT_ATTR_APPLICATION_INFO, 656 mPkgInfo.applicationInfo); 657 newIntent.setData(mPackageURI); 658 newIntent.setClass(this, InstallAppProgress.class); 659 String installerPackageName = getIntent().getStringExtra( 660 Intent.EXTRA_INSTALLER_PACKAGE_NAME); 661 if (mOriginatingURI != null) { 662 newIntent.putExtra(Intent.EXTRA_ORIGINATING_URI, mOriginatingURI); 663 } 664 if (mReferrerURI != null) { 665 newIntent.putExtra(Intent.EXTRA_REFERRER, mReferrerURI); 666 } 667 if (mOriginatingUid != VerificationParams.NO_UID) { 668 newIntent.putExtra(Intent.EXTRA_ORIGINATING_UID, mOriginatingUid); 669 } 670 if (installerPackageName != null) { 671 newIntent.putExtra(Intent.EXTRA_INSTALLER_PACKAGE_NAME, 672 installerPackageName); 673 } 674 if (getIntent().getBooleanExtra(Intent.EXTRA_RETURN_RESULT, false)) { 675 newIntent.putExtra(Intent.EXTRA_RETURN_RESULT, true); 676 newIntent.addFlags(Intent.FLAG_ACTIVITY_FORWARD_RESULT); 677 } 678 if(localLOGV) Log.i(TAG, "downloaded app uri="+mPackageURI); 679 startActivity(newIntent); 680 finish(); 681 } else { 682 mScrollView.pageScroll(View.FOCUS_DOWN); 683 } 684 } else if(v == mCancel) { 685 // Cancel and finish 686 setResult(RESULT_CANCELED); 687 finish(); 688 } 689 } 690 } 691