Titanium JIRA Archive
Titanium SDK/CLI (TIMOB)

[TIMOB-23476] Android: constants are writable

GitHub Issuen/a
TypeBug
PriorityCritical
StatusClosed
ResolutionFixed
Resolution Date2016-06-27T17:17:57.000+0000
Affected Version/sn/a
Fix Version/sRelease 6.0.0
ComponentsAndroid
Labelsn/a
ReporterChristopher Williams
AssigneeChristopher Williams
Created2016-06-03T19:01:06.000+0000
Updated2016-08-12T22:58:02.000+0000

Description

Constants in Android are able to be "overwritten". Things like Ti.App.EVENT_ACCESSIBILITY_ANNOUNCEMENT should be truly constant and the user shouldn't be able to overwrite the value or delete the property. Currently you can "overwrite" the value:
Ti.API.info('original value: ' + Ti.App.EVENT_ACCESSIBILITY_ANNOUNCEMENT);
Ti.App.EVENT_ACCESSIBILITY_ANNOUNCEMENT = 'my very own made-up value';
Ti.API.info('modified value: ' + Ti.App.EVENT_ACCESSIBILITY_ANNOUNCEMENT);
' I think the underlying cause here is actually different than TIMOB-23475. I Believe this is because we hang 'constants' on the prototype of the proxy (i.e. Object.getPrototypeOf(Ti.App);) while the global object living at Ti.App is an instance. So what's happening looks to be "property shadowing" where we're actually adding a new EVENT_ACCESSIBILITY_ANNOUNCEMENT property with our own value onto the instance of Ti.App that lives in the global namespace at Ti.App. This instance property "shadows" the original constant declared on the prototype. To prove my point, calling Object.getPrototypeOf(Ti.App) gives:
{"Properties":{"apiName":"Ti.App.Properties","bubbleParent":true},"Android":{"bubbleParent":true,"launchIntent":{"action":null,"bubbleParent":true,"packageName":"dfg.df","data":null,"type":null,"apiName":"Ti.Android.Intent","className":"dfg.df.ExampleActivity","flags":268435456},"appVersionCode":1,"appVersionName":"1.0","apiName":"Ti.App.Android","R":{"bubbleParent":true,"apiName":"Ti.Android.R"}},"EVENT_ACCESSIBILITY_ANNOUNCEMENT":"accessibilityannouncement","EVENT_ACCESSIBILITY_CHANGED":"accessibilitychanged"}
You can clearly see the constants there. It makes sense to hang the constants at the "prototype" level since they're supposed to be "class-level/static" constants and we shouldn't need to have every instance hold a copy. However, it looks like we're not preventing shadowing properly (even though it appears we're setting the constant property attributes to ReadOnly|DontDelete). See https://github.com/getify/You-Dont-Know-JS/issues/91 for discussion on cases where there seems to be prevented shadowing. One possible solution may be to do an Object.seal() on all our proxies after they're set up. This marks all properties as DontDelete and prevents new properties from being added.

Comments

  1. Christopher Williams 2016-06-03

    Note that our V8 version is way out of date, and using the latest V8 may help bring us the behavior described in that link whereby a non-writable property on the prototype prevents shadowing on instances?
  2. Christopher Williams 2016-06-03

    Just tested using the new V8 locally and can confirm that this _does_ fix the behavior for shadowing constants marked as read-only on the prototype. So, once TIMOB-23310 is merged, this will be fixed as well.
  3. Lokesh Choudhary 2016-08-12

    Verified the fix. Constants do not get overwritten anymore. Closing. Environment: Appc Studio : 4.7.0.201607250649 Ti SDK : 6.0.0.v20160811221444 Ti CLI : 5.0.9 Alloy : 1.9.1 MAC El Capitan : 10.11.6 Appc NPM : 4.2.7 Appc CLI : 6.0.0-24 Node: 4.4.4 Nexus 5 - Android 6.0.1

JSON Source