Tuesday, August 16, 2016

5 Tips to help you improve game-as-a-service monetization

Posted by Moonlit Wang, Partner Development Manager at Google Play
Games, & Tammy Levy, Director of Product for Mobile at href="http://developers.kongregate.com/">Kongregate



In today’s world of game-as-a-service on mobile, the lifetime value of a player
is a lot more complex, where revenue is now the sum of many micro transactions
instead of a single purchase with traditional console games.


Of course you don’t need a sophisticated statistical model to understand that
the more time a player invests in your game, and the more money they spend, the
greater their LTV. But how can you design and improve monetization as a mobile
game developer? Here are 5 tips to help you improve game-as-a-service
monetization, with best practice examples from mobile games publisher, href="https://play.google.com/store/apps/dev?id=7580247376460930437&hl=en_GB">Kongregate:


1. Track player behavior metrics that have a strong and positive correlation with LTV




  • D1, D7, D30 retention indicates how well a casual player
    can be converted into a committed fan.
  • Session length and frequency measures user engagement and
    how fun your game is.
  • Completion rate at important milestones can measure and
    pinpoint churn.
  • Buyer and repeated buyer conversion, represents your most
    valuable user segment.


2. Optimize for long-term engagement and delight your best players

Retention is the first metric that can distinguish great games from mediocre
ones. Games with higher retention rates throughout the user’ lifecycle, monetize
better consistently. Retention is king, and more importantly, long-term
retention should be prioritized.
Therefore, when designing your game,
aim to create a sophisticated and engaging experience to delight your most
committed fans.



[This chart shows the retention of top games / apps over time]





  • When considering long term retention, focus on achieving a strong D30, but
    also look beyond the first 30 days. Measure long term retention
    by assessing the following rates: D30 to D60, D30 to D90, and D30 to D180. The
    higher the rate, the stickier your game is in the long term, which will increase
    your LTV.
  • Players are willing to pay a fixed amount of money per hour of “fun”, so
    think about updates when designing your game, to make
    the content rich and fun for those who will play at very high levels and
    spend the most time within your game
    , don’t gate your players or hinder
    their in-game progression.
  • Use the href="http://android-developers.blogspot.com/2016/01/new-features-to-better-understand.html">Google
    Play Games Services - Funnel Report
    to help you track different
    milestone completion rates in your games, so you can identify drop off points
    and reduce churn
.
3. Increase buyer conversion through targeted offers



First-time buyer conversion is the most important as player churn rate
drops significantly after the first purchase
, but stays relatively flat
regardless of the amount spent. Also, past purchase behavior is the best
predictor of future purchases. Find your first-time and repeated buyer
conversion rate directly in the href="https://developer.android.com/distribute/users/user-acquisition.html">Developer
Console.






  • Use A/B testing to find the price that will maximize your total
    revenue
    . Different people have different willingness to pay for
    a given product
    and the tradeoff between price and quantity is
    different for different products, so don’t decrease prices blindly.
  • Tailor your in-game experience as well as in-app purchase offersbased on the player’s predicted probability to spend using the href="https://developers.google.com/games/services/android/stats">Player Stats
    API
    ,
    which
    predicts players churn and spend.




For example, in href="https://play.google.com/store/apps/developer?id=Kongregate&hl=en_GB&e=-EnableAppDetailsPageRedesign">Kongregate’s
game href="https://play.google.com/store/apps/details?id=com.kongregate.mobile.spellstone.google&hl=en_GB">Spellstone,
testing two pricing points for a promotion called Shard Bot, which provides
players with a daily “drip” of Shards (the premium currency) for 30 days, showed
players had a much stronger preference for the higher priced
pack.
The first pack, Shard Bot, priced at $4, granted players 5 daily
shards, and the second pack, the Super Shard Bot, was priced at $8 and granted
players 10 daily shards.





[Two week test results showing preference for the more expensive pack, which also generated more revenue]




Kongregate decided to keep the higher priced Super Shard Bot in the store,
although both packs resulted in very similar retention rates:




4. As well as what monetization features to implement, take into consideration why, when and how to do so





  • Why: “Buyer intent” is most important. Any item with a
    price tag should serve to enhance your players in-game experience.
    For
    example, a new map, a new power, something exciting and additional to the free
    experience. Don’t gate your players with a purchase-only item as happy users
    means more time spent with your game, which will lead to higher
    revenue. Educate users by gifting some free premium goods and currency during the tutorial, and let users experience the benefit first.





  • When: Time offers based on when users may need it.
    If your IAP is to continue gameplay after timeout, then you should surface it
    right when the timer ends. If your IAP is to offer premium equipment, then you
    should surface it when users gear up their characters. The offer should be
    contextually relevant, such that the content should cater to the player’s
    current status and needs in-game.




    In particular, Starter Packs or New Buyer Promos need to be well timed. Players
    need to understand the value and importance of all the items before they are
    shown the promotion. If surfaced too early, players will not feel compelled to
    purchase. If surfaced too late, the offer will not be compelling enough. The
    Starter Pack should appear within 3 to 5 sessions since install, depending on
    your game. Additionally, limiting its availability to 3 to 5 days will urge
    players to make a quicker purchase decision.









  • Powerful cards that have an immediate effect in battle
  • High rarity upgrade materials to upgrade your card deck
  • A generous amount of soft currency that can be used in all areas of the game
  • A generous amount of hard currency so players can purchase premium store
    items
  • Rare upgrade materials for Heroes




[Example starter pack offer in Battle Hands]


Thanks to the strength of the promotion over 50% of players choose the Starter Pack instead of the regular gems offerings:






  • How: There are many ways you can implement premium content and goods in your game, such as power-ups, characters, equipment, maps, hints, chapters etc. The two most impactful monetization designs are:


      Gacha - There are many ways to design, present and balance gacha but the key is to have randomized rewards, which allows you to sell extremely powerful items that players want without having to charge really high prices per purchase.



[Example of randomized rewards in Raid Brigade’s boxes]



      LiveOps - Limited time content on a regular cadence will also create really compelling opportunities for the players to both engage further with the game and invest in the game. For instance, Adventure Capitalist has been releasing regular limited themed time events with their spin on the permanent content, their own progression, achievements and IAP promotions.




[Example timed event for Adventure Capitalist]



Through this initiative, the game has seen regular increases in both engagement and revenue during event times without affecting the non-event periods:




[Timed events drastically increase engagement and revenue without lowering the baseline average over time]


5. Take into account local prices and pricing models



Just like different people have different willingness-to-pay, different markets have different purchasing powers.



    • Test what price points make sense for local consumers in each major market.
      Don’t just apply an umbrella discount, find the price points that maximize total
      revenue.
    • Consider charm pricing but remember it doesn’t work everywhere.For example, in the United States, prices always end in $x.99, but
      that’s not the case in Japan and Korea, where rounded numbers are used. Pricing
      in accordance to the local norm signals to the customers that you care and
      designed the game with them in mind. The Google Developer Console now
      automatically applies href="https://support.google.com/googleplay/android-developer/answer/6334373?hl=en&ref_topic=6075663">local
      pricing conventions
      of each currency for you.




href="http://android-developers.blogspot.co.uk/2016/06/android-developer-story-vietnamese.html">Check
out the Android Developer Story from games developer, Divmob
, who improved
their game’s monetization threefold simply by adopting sub-dollar pricing
strategies. Also, href="https://play.google.com/store/books/details/Google_Inc_The_Building_for_Billions_Playbook_for?id=cJEjDAAAQBAJ&e=-EnableAppDetailsPageRedesign">learn
more best practices about building for billions
to get more tips on
monetization.




href="https://play.google.com/store/apps/details?id=com.google.android.apps.secrets">Get
the Playbook for Developers app
and stay up-to-date with more features and
best practices that will help you grow a successful business on Google Play.

Announcing Android add-ons for Docs and Sheets




We know many of you consider your mobile device as your primary tool to consume business information, but what if you could use it to get more work done, from anywhere?

We’re excited to introduce Android add-ons for Docs and Sheets, a new way for you to do just that—whether it’s readying a contract you have for e-signature from your phone, or pulling in CRM data on your tablet for some quick analysis while waiting for your morning coffee, Android add-ons can help you accomplish more.


Get more done with your favorite third-party apps, no matter where you are


We’ve worked with eight integration partners who have created seamless integrations for Docs and Sheets. Here’s a preview of just a few of them:




  • DocuSign - Trigger or complete a signing process from Docs or Sheets, and save the executed document to Drive. Read more here.





DocuSign lets you easily create signature envelopes right from Google Docs



  • ProsperWorks - Import your CRM data to create and update advanced dashboards, reports and graphs on Sheets, right from your device. Read more here.

  • AppSheet - Create powerful mobile apps directly from your data in Sheets instantly — no coding required. Read more here.

  • Scanbot - Scan your business documents using built-in OCR, and insert their contents into Docs as editable text. Read more here.





You can find these add-ons and many more, including PandaDoc, ZohoCRM, Teacher Aide, EasyBib and Classroom in our Google Play collection as well as directly from the add-on menus in Docs or Sheets.







Try them out today, and see how much more you can do.





Calling all developers: try our developer preview today!


As you can see from above, Android add-ons offer a great opportunity to build
innovative integrations and reach Docs and Sheets users around the world.
They’re basically Android apps that connect with href="http://developers.google.com/apps-script?utm_campaign=android_discussion_googledocs_072816&utm_source=anddev&utm_medium=blog">Google Apps Script projects
on the server-side, allowing them to access and manipulate data from Google Docs
or Sheets using standard Apps Script techniques. Check out href="https://developers.google.com/apps-script/add-ons/mobile?utm_campaign=android_discussion_googledocs_072816&utm_source=anddev&utm_medium=blog">our
documentation
which includes href="https://developers.google.com/apps-script/add-ons/mobile/mobile-style?utm_campaign=android_discussion_googledocs_072816&utm_source=anddev&utm_medium=blog">UI
guidelines
as well as href="https://developers.google.com/apps-script/add-ons/mobile/?utm_campaign=android_discussion_googledocs_072816&utm_source=anddev&utm_medium=blog#see_what_you_can_make">sample
code
to get you started. We’ve also made it easy for you to publish your
apps with the Apps Script editor.


Android add-ons are available today as a developer preview. We look forward to
seeing what you build!

Expand Your Global Reach on Google Play With New Language and Country Analytics



With users in 190 countries around the world, Google Play offers you a truly
global audience for your apps and games. Localization is one of the most
powerful ways to connect with people in different places, which is why we
launched translation support for in-app purchase and Universal App Campaigns
earlier this year. With over 30 language translation options available via the
Developer Console, we updated our app translation service to help you select the
most relevant languages, making it quick and easy to get started.


With the launch of new language and country analytics, you gain access to app
install analysis on Google Play, including:

  • Information on the top languages and countries where apps have been
    installed, broken down to the level of your app’s category
  • The percentage of installs that come from users of those languages
  • Further information to help inform your go-to-market plans for these
    countries





To make ordering translations easier, we show language bundles that you can add
to your order in a single click.


To get started, select Manage translations -> Purchase
translations
from the Store Listing page in the href="https://play.google.com/apps/publish/">Google Play Developer Console.

New features for reviews and experiments in Google Play Developer Console app



With over one million apps published through the Google Play Developer Console,
we know how important it is to publish with confidence, acquire users, learn
about them, and manage your business. Whether reacting to a critical performance
issue or responding to a negative review, checking on your apps when and where
you need to is invaluable.


The href="https://play.google.com/store/apps/details?id=com.google.android.apps.playconsole&hl=en">Google
Play Developer Console app
, launched in May, has already helped thousands of
developers stay informed of crucial business updates on the go.


We’re excited to tell you about new features, available today:


Receive notifications about new reviews





Use filters to find the reviews you want





Review and apply store listing experiment results





Increase the percent of a staged rollout or halt a bad staged
rollout






Download the href="https://play.google.com/store/apps/details?id=com.google.android.apps.playconsole">Developer
Console app on Google Play
and stay on top of your apps and games, wherever
you are! Also, get the Playbook for Developers app to stay up-to-date with more features and best practices that will help you grow a successful business on Google Play.

Wednesday, July 27, 2016

Android Developer Story: Culture Alley reaches millions of English learners on Google Play

Posted by Lily Sheringham, Google Play team


href="https://play.google.com/store/apps/developer?id=Culture%20Alley&hl=en_GB">Culture
Alley
developed the app href="https://play.google.com/store/apps/details?id=com.CultureAlley.japanese.english&hl=en_GB&e=-EnableAppDetailsPageRedesign">Hello
English
to help Indians learn English through gamification, supporting over
15 dialects. More than 13 million people now use Hello English in India and
around the world.


Hear Nishant Patni, Founder & CEO and Pranshu Bhandari, Co-Founder, explain how
they optimized the app to address challenges faced by emerging markets. Learn
how they used various Google Play tools to address varying levels of
connectivity and device capabilities, and improve user retention.



href="https://play.google.com/store/books/details/Google_Inc_The_Building_for_Billions_Playbook_for?id=cJEjDAAAQBAJ&e=-EnableAppDetailsPageRedesign">Learn
more best practices about building for billions
and href="https://www.youtube.com/watch?v=PfwHq8w9GBc&list=PLWz5rJ2EKKc_ElGrEtiEXc83m1SeYu3-Q&index=11">watch
the ‘10 tips to build an app for billions of users
’ video to get more tips.
Also, get the
Playbook for Developers app
and stay up-to-date with more features and best
practices that will help you grow a successful business on Google Play.

Wednesday, July 20, 2016

Strictly Enforced Verified Boot with Error Correction


Posted by Sami Tolvanen, Software Engineer


Overview



Android uses multiple layers of protection to keep users safe. One of these
layers is verified
boot, which improves security by using cryptographic integrity checking to
detect changes to the operating system. Android has href="https://g.co/ABH">alerted about system integrity since Marshmallow,
but starting with devices first shipping with Android 7.0, we require verified
boot to be strictly enforcing. This means that a device with a corrupt boot
image or verified partition will not boot or will boot in a limited capacity
with user consent. Such strict checking, though, means that non-malicious data
corruption, which previously would be less visible, could now start affecting
process functionality more.


By default, Android verifies large partitions using the dm-verity kernel driver,
which divides the partition into 4 KiB blocks and verifies each block when read,
against a signed hash tree. A detected single byte corruption will therefore
result in an entire block becoming inaccessible when dm-verity is in enforcing
mode, leading to the kernel returning EIO errors to userspace on verified
partition data access.


This post describes our work in improving dm-verity robustness by introducing
forward error correction (FEC), and explains how this allowed us to make the
operating system more resistant to data corruption. These improvements are
available to any device running Android 7.0 and this post reflects the default
implementation in AOSP that we ship on our Nexus devices.

Error-correcting codes



Using forward error correction, we can detect and correct errors in source data
by shipping redundant encoding data generated using an error-correcting code.
The exact number of errors that can be corrected depends on the code used and
the amount of space allocated for the encoding data.


href="https://en.wikipedia.org/wiki/Reed%E2%80%93Solomon_error_correction">Reed-Solomon
is one of the most commonly used error-correcting code families, and is readily
available in the Linux kernel, which makes it an obvious candidate for
dm-verity. These codes can correct up to ⌊t/2⌋ unknown errors and up to
t known errors, also called href="https://en.wikipedia.org/wiki/Erasure_code">erasures, when t
encoding symbols are added.


A typical RS(255, 223) code that generates 32 bytes of encoding data for every
223 bytes of source data can correct up to 16 unknown errors in each 255 byte
block. However, using this code results in ~15% space overhead, which is
unacceptable for mobile devices with limited storage. We can decrease the space
overhead by sacrificing error correction capabilities. An RS(255, 253) code can
correct only one unknown error, but also has an overhead of only 0.8%.



An additional complication is that block-based storage corruption often occurs
for an entire block and sometimes spans multiple consecutive blocks. Because
Reed-Solomon is only able to recover from a limited number of corrupted bytes
within relatively short encoded blocks, a naive implementation is not going to
be very effective without a huge space overhead.

Recovering from consecutive corrupted blocks



In the changes we made to href="https://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/commit/?id=a739ff3f543afbb4a041c16cd0182c8e8d366e70">dm-verity
for Android 7.0, we used a technique called interleaving to allow us to recover
not only from a loss of an entire 4 KiB source block, but several consecutive
blocks, while significantly reducing the space overhead required to achieve
usable error correction capabilities compared to the naive implementation.


Efficient interleaving means mapping each byte in a block to a separate
Reed-Solomon code, with each code covering N bytes across the corresponding N
source blocks. A trivial interleaving where each code covers a consecutive
sequence of N blocks already makes it possible for us to recover from the
corruption of up to (255 - N) / 2 blocks, which for RS(255, 223) would
mean 64 KiB, for example.


An even better solution is to maximize the distance between the bytes covered by
the same code by spreading each code over the entire partition, thereby
increasing the maximum number of consecutive corrupted blocks an RS(255, N) code
can handle on a partition consisting of T blocks to ⌈T/N⌉ × (255 -
N) / 2
.




Interleaving with distance D and block size B.


An additional benefit of interleaving, when combined with the integrity
verification already performed by dm-verity, is that we can tell exactly where
the errors are in each code. Because each byte of the code covers a different
source block—and we can verify the integrity of each block using the existing
dm-verity metadata—we know which of the bytes contain errors. Being able to
pinpoint erasure locations allows us to effectively double our error correction
performance to at most ⌈T/N⌉ × (255 - N) consecutive blocks.


For a ~2 GiB partition with 524256 4 KiB blocks and RS(255, 253), the maximum
distance between the bytes of a single code is 2073 blocks. Because each code
can recover from two erasures, using this method of interleaving allows us to
recover from up to 4146 consecutive corrupted blocks (~16 MiB). Of course, if
the encoding data itself gets corrupted or we lose more than two of the blocks
covered by any single code, we cannot recover anymore.


While making error correction feasible for block-based storage, interleaving
does have the side effect of making decoding slower, because instead of reading
a single block, we need to read multiple blocks spread across the partition to
recover from an error. Fortunately, this is not a huge issue when combined with
dm-verity and solid-state storage as we only need to resort to decoding if a
block is actually corrupted, which still is rather rare, and random access reads
are relatively fast even if we have to correct errors.

Conclusion



Strictly enforced verified boot improves security, but can also reduce
reliability by increasing the impact of disk corruption that may occur on
devices due to software bugs or hardware issues.


The new error correction feature we developed for dm-verity makes it possible
for devices to recover from the loss of up to 16-24 MiB of consecutive blocks
anywhere on a typical 2-3 GiB system partition with only 0.8% space overhead and
no performance impact unless corruption is detected. This improves the security
and reliability of devices running Android 7.0.

Friday, July 8, 2016

Changes to Trusted Certificate Authorities in Android Nougat

Changes to Trusted Certificate Authorities in Android Nougat

Posted by Chad Brubaker, Android Security team




In Android Nougat, we’ve changed how Android handles trusted certificate
authorities (CAs) to provide safer defaults for secure app traffic. Most apps
and users should not be affected by these changes or need to take any action.
The changes include:


  • Safe and easy APIs to trust custom CAs.
  • Apps that target API Level 24 and above no longer trust user or admin-added
    CAs for secure connections, by default.
  • All devices running Android Nougat offer the same standardized set of system
    CAs—no device-specific customizations.


For more details on these changes and what to do if you’re affected by them,
read on.


Safe and easy APIs



Apps have always been able customize which certificate authorities they trust.
However, we saw apps making mistakes due to the complexities of the Java TLS
APIs. To address this we href="https://developer.android.com/preview/features/security-config.html">improved
the APIs for customizing trust.


User-added CAs



Protection of all application data is a key goal of the Android application
sandbox. Android Nougat changes how applications interact with user- and
admin-supplied CAs. By default, apps that target API level 24 will—by design—not
honor such CAs unless the app explicitly opts in. This safe-by-default setting
reduces application attack surface and encourages consistent handling of network
and file-based application data.


Customizing trusted CAs



Customizing the CAs your app trusts on Android Nougat is easy using the Network
Security Config. Trust can be specified across the whole app or only for
connections to certain domains, as needed. Below are some examples for trusting
a custom or user-added CA, in addition to the system CAs. For more examples and
details, see href="https://developer.android.com/preview/features/security-config.html">the
full documentation.


Trusting custom CAs for debugging



To allow your app to trust custom CAs only for local debugging, include
something like this in your Network Security Config. The CAs will only be
trusted while your app is marked as debuggable.


<network-security-config>  
<debug-overrides>
<trust-anchors>
<!-- Trust user added CAs while debuggable only -->
<certificates src="user" />
</trust-anchors>
</domain-config>
</network-security-config>


Trusting custom CAs for a domain



To allow your app to trust custom CAs for a specific domain, include something
like this in your Network Security Config.



<network-security-config>  
<domain-config>
<domain includeSubdomains="true">internal.example.com</domain>
<trust-anchors>
<!-- Only trust the CAs included with the app
for connections to internal.example.com -->
<certificates src="@raw/cas" />
</trust-anchors>
</domain-config>
</network-security-config>


Trusting user-added CAs for some domains



To allow your app to trust user-added CAs for multiple domains, include
something like this in your Network Security Config.



<network-security-config>  
<domain-config>
<domain includeSubdomains="true">userCaDomain.com</domain>
<domain includeSubdomains="true">otherUserCaDomain.com</domain>
<trust-anchors>
<!-- Trust preinstalled CAs -->
<certificates src="system" />
<!-- Additionally trust user added CAs -->
<certificates src="user" />
</trust-anchors>
</domain-config>
</network-security-config>


Trusting user-added CAs for all domains except some



To allow your app to trust user-added CAs for all domains, except for those
specified, include something like this in your Network Security Config.



<network-security-config>  
<base-config>
<trust-anchors>
<!-- Trust preinstalled CAs -->
<certificates src="system" />
<!-- Additionally trust user added CAs -->
<certificates src="user" />
</trust-anchors>
</base-config>
<domain-config>
<domain includeSubdomains="true">sensitive.example.com</domain>
<trust-anchors>
<!-- Only allow sensitive content to be exchanged
with the real server and not any user or
admin configured MiTMs -->
<certificates src="system" />
<trust-anchors>
</domain-config>
</network-security-config>


Trusting user-added CAs for all secure connections



To allow your app to trust user-added CAs for all secure connections, add this
in your Network Security Config.



<network-security-config>  
<base-config>
<trust-anchors>
<!-- Trust preinstalled CAs -->
<certificates src="system" />
<!-- Additionally trust user added CAs -->
<certificates src="user" />
</trust-anchors>
</base-config>
</network-security-config>


Standardized set of system-trusted CAs



To provide a more consistent and more secure experience across the Android
ecosystem, beginning with Android Nougat, compatible devices trust only the
standardized system CAs maintained in href="https://android.googlesource.com/platform/system/ca-certificates/">AOSP.



Previously, the set of preinstalled CAs bundled with the system could vary from
device to device. This could lead to compatibility issues when some devices did
not include CAs that apps needed for connections as well as potential security
issues if CAs that did not meet our security requirements were included on some
devices.


What if I have a CA I believe should be included on Android?



First, be sure that your CA needs to be included in the system. The preinstalled
CAs are only for CAs that meet our security requirements
because they affect the secure connections of most apps on the device. If you
need to add a CA for connecting to hosts that use that CA, you should instead
customize your apps and services that connect to those hosts. For more
information, see the Customizing trusted CAs section above.



If you operate a CA that you believe should be included in Android, first
complete the Mozilla CA
Inclusion Process
and then file a href="https://code.google.com/p/android/issues/entry">feature request
against Android to have the CA added to the standardized set of system CAs.


Friday, July 1, 2016

Building for Billions

Posted by Sam Dutton, Ankur Kotwal, Developer Advocates; Liz Yepsen, Program Manager






‘TOP-UP WARNING.’ ‘NO CONNECTION.’ ‘INSUFFICIENT BANDWIDTH TO PLAY THIS
RESOURCE.’



These are common warnings for many smartphone users around the world.



To build products that work for billions of users, developers must address key
challenges: limited or intermittent connectivity, device compatibility, varying
screen sizes, high data costs, short-lived batteries. We first presented href="https://developers.google.com/billions/?utm_campaign=android_discussion_billions_063016&utm_source=anddev&utm_medium=blog">developers.google.com/billions
and related Android and Web resources at Google I/O last month, and today you
can watch the video presentations about href="https://www.youtube.com/watch?v=vaEV8bNi1Dw">Android or the href="https://www.youtube.com/watch?v=E6hGubMkNfM">Web.



These best practices can help developers reach billions by delivering
exceptional performance across a range of connections, data plans, and devices.
g.co/dev/billions will
help you:



Seamlessly transition between slow, intermediate, and offline
environments



Your users move from place to place, from speedy wireless to patchy or expensive
data. Manage these transitions by storing data, queueing requests, optimizing
image handling, and performing core functions entirely offline.



Provide the right content for the right context



Keep context in mind - how and where do your users consume your content?
Selecting text and media that works well across different viewport sizes,
keeping text short (for scrolling on the go), providing a simple UI that doesn’t
distract from content, and removing redundant content can all increase
perception of your app’s quality while giving real performance gains
like reduced data transfer. Once these practices are in place, localization
options can grow audience reach and increase engagement.



Optimize for mobile hardware



Ensure your app or Web content is served and runs well for your widest possible
addressable market, covering all actively used OS versions, while still
following best practices, by testing on virtual or actual devices in target
markets. Native Android apps should set minimum and target SDKs. Also, remember
low cost phones have smaller amounts of RAM; apps should therefore adjust usage
accordingly and minimize background running. For in-depth information on
minimizing APK size, check out this href="https://medium.com/@wkalicinski/smallerapk-part-8-native-libraries-open-from-apk-fc22713861ff">series
of Medium posts. On the Web, optimize JavaScript CPU usage, avoid raster
image rendering, and minimize resource requests. Find out more href="https://developers.google.com/web/fundamentals/performance/?utm_campaign=android_discussion_billions_063016&utm_source=anddev&utm_medium=blog">here.



Reduce battery consumption



Low cost phones usually have shorter battery life. Users are sensitive to
battery consumption levels and excessive consumption can lead to a high
uninstall rate or avoidance of your site. Benchmark your battery usage against
sessions on other pages or apps, or using tools such as Battery Historian, and
avoid long-running processes which drain batteries.



Conserve data usage



Whatever you’re building, conserve data usage in three simple steps: understand
loading requirements, reduce the amount of data required for interaction, and
streamline navigation so users get what they want quickly. Conserving data on
behalf of your users (and with native apps, offering configurable network usage)
helps retain data-sensitive users -- especially those on prepaid plans or
contracts with limited data -- as even “unlimited” plans can become expensive
when roaming or if unexpected fees are applied.



Have another insight, or a success launching in low-connectivity conditions or
on low-cost devices? Let us know on our href="https://plus.sandbox.google.com/+GoogleDevelopers/posts/WffV23WSrc8">G+
post.

Tuesday, June 28, 2016

Android changes for NDK developers

Android changes for NDK developers

Posted by Dmitry Malykhanov, Developer Advocate




Related to other improvements to the Android platform, the dynamic linker in
Android M and N has stricter requirements for writing clean, cross-platform
compatible native code in order to load. It is necessary that an application’s
native code follows the rules and recommendations in order to ensure a smooth
transition to recent Android releases.



Below we outline in detail each individual change related to native code
loading, the consequences and steps you can take to avoid issues.



Required tools: there is an <arch>-linux-android-readelf binary (e.g.
arm-linux-androideabi-readelf or i686-linux-android-readelf) for each
architecture in the NDK (under toolchains/), but you can use readelf for any
architecture, as we will be doing basic inspection only. On Linux you need to
have the “binutils” package installed for readelf, and “pax-utils” for scanelf.


Private API (Enforced since API 24)



Native libraries must use only href="http://developer.android.com/ndk/guides/stable_apis.html?utm_campaign=android_discussion_ndkchanges_062716&utm_source=anddev&utm_medium=blog">public API,
and must not link against non-NDK platform libraries. Starting with API 24 this
rule is enforced and applications are no longer able to load non-NDK platform
libraries. The rule is enforced by the dynamic linker, so non-public libraries
are not accessible regardless of the way code tries to load them:
System.loadLibrary(...), DT_NEEDED entries, and direct calls to dlopen(...) will
fail in exactly the same way.



Users should have a consistent app experience across updates, and developers
shouldn’t have to make emergency app updates to handle platform changes. For
that reason, we recommend against using private C/C++ symbols. Private symbols
aren’t tested as part of the Compatibility Test Suite (CTS) that all Android
devices must pass. They may not exist, or they may behave differently. This
makes apps that use them more likely to fail on specific devices, or on future
releases --- as many developers found when Android 6.0 Marshmallow switched from
OpenSSL to BoringSSL.



In order to reduce the user impact of this transition, we’ve identified a set of
libraries that see significant use from Google Play’s most-installed apps, and
that are feasible for us to support in the short term (including
libandroid_runtime.so, libcutils.so, libcrypto.so, and libssl.so). In order to
give you more time to transition, we will temporarily support these libraries;
so if you see a warning that means your code will not work in a future release
-- please fix it now!



$ readelf --dynamic libBroken.so | grep NEEDED
0x00000001 (NEEDED) Shared library: [libnativehelper.so]
0x00000001 (NEEDED) Shared library: [libutils.so]
0x00000001 (NEEDED) Shared library: [libstagefright_foundation.so]
0x00000001 (NEEDED) Shared library: [libmedia_jni.so]
0x00000001 (NEEDED) Shared library: [liblog.so]
0x00000001 (NEEDED) Shared library: [libdl.so]
0x00000001 (NEEDED) Shared library: [libz.so]
0x00000001 (NEEDED) Shared library: [libstdc++.so]
0x00000001 (NEEDED) Shared library: [libm.so]
0x00000001 (NEEDED) Shared library: [libc.so]


Potential problems: starting from API 24 the dynamic linker will not load
private libraries, preventing the application from loading.



Resolution: rewrite your native code to rely only on public API. As a short term
workaround, platform libraries without complex dependencies (libcutils.so) can
be copied to the project. As a long term solution the relevant code must be
copied to the project tree. SSL/Media/JNI internal/binder APIs should not be
accessed from the native code. When necessary, native code should call
appropriate public Java API methods.



A complete list of public libraries is available within the NDK, under
platforms/android-API/usr/lib.


Note: SSL/crypto is a special case, applications must NOT use platform libcrypto
and libssl libraries directly, even on older platforms. All applications should
use href="http://developer.android.com/training/articles/security-gms-provider.html?utm_campaign=android_discussion_ndkchanges_062716&utm_source=anddev&utm_medium=blog">GMS
Security Provider to ensure they are protected from known vulnerabilities.


Missing Section Headers (Enforced since API 24)



Each ELF file has additional information contained in the section headers. These
headers must be present now, because the dynamic linker uses them for sanity
checking. Some developers try to strip them in an attempt to obfuscate the
binary and prevent reverse engineering. (This doesn’t really help because it is
possible to reconstruct the stripped information using widely-available tools.)



$ readelf --header libBroken.so | grep 'section headers'
Start of section headers: 0 (bytes into file)
Size of section headers: 0 (bytes)
Number of section headers: 0
$


Resolution: remove the extra steps from your build that strip section headers.


Text Relocations (Enforced since API 23)



Starting with API 23, shared objects must not contain text relocations. That is,
the code must be loaded as is and must not be modified. Such an approach reduces
load time and improves security.



The usual reason for text relocations is non-position independent hand-written
assembler. This is not common. Use the href="https://wiki.gentoo.org/wiki/Hardened/Textrels_Guide#Finding_broken_object_code">scanelf
tool as described in href="http://developer.android.com/about/versions/marshmallow/android-6.0-changes.html?utm_campaign=android_discussion_ndkchanges_062716&utm_source=anddev&utm_medium=blog#behavior-runtime">our
documentation for further diagnostics:



$ scanelf -qT libTextRel.so
libTextRel.so: (memory/data?) [0x15E0E2] in (optimized out: previous simd_broken_op1) [0x15E0E0]
libTextRel.so: (memory/data?) [0x15E3B2] in (optimized out: previous simd_broken_op2) [0x15E3B0]
[skipped the rest]


If you have no scanelf tool available, it is possible to do a basic check with
readelf instead, look for either a TEXTREL entry or the TEXTREL flag. Either
alone is sufficient. (The value corresponding to the TEXTREL entry is irrelevant
and typically 0 --- simply the presence of the TEXTREL entry declares that the
.so contains text relocations). This example has both indicators present:



$ readelf --dynamic libTextRel.so | grep TEXTREL
0x00000016 (TEXTREL) 0x0
0x0000001e (FLAGS) SYMBOLIC TEXTREL BIND_NOW
$


Note: it is technically possible to have a shared object with the TEXTREL
entry/flag but without any actual text relocations. This doesn’t happen with the
NDK, but if you’re generating ELF files yourself make sure you’re not generating
ELF files that claim to have text relocations, because the Android dynamic
linker trusts the entry/flag.



Potential problems: Relocations enforce code pages being writable, and
wastefully increase the number of dirty pages in memory. The dynamic linker has
issued warnings about text relocations since Android K (API 19), but on API 23
and above it refuses to load code with text relocations.



Resolution: rewrite assembler to be position independent to ensure no text
relocations are necessary. Check the href="https://wiki.gentoo.org/wiki/Hardened/Textrels_Guide">Gentoo
documentation for cookbook recipes.


Invalid DT_NEEDED Entries (Enforced since API 23)



While library dependencies (DT_NEEDED entries in the ELF headers) can be
absolute paths, that doesn’t make sense on Android because you have no control
over where your library will be installed by the system. A DT_NEEDED entry
should be the same as the needed library’s SONAME, leaving the business of
finding the library at runtime to the dynamic linker.



Before API 23, Android’s dynamic linker ignored the full path, and used only the
basename (the part after the last ‘/’) when looking up the required libraries.
Since API 23 the runtime linker will honor the DT_NEEDED exactly and so it won’t
be able to load the library if it is not present in that exact location on the
device.



Even worse, some build systems have bugs that cause them to insert DT_NEEDED
entries that point to a file on the build host, something that
cannot be found on the device.



$ readelf --dynamic libSample.so | grep NEEDED
0x00000001 (NEEDED) Shared library: [libm.so]
0x00000001 (NEEDED) Shared library: [libc.so]
0x00000001 (NEEDED) Shared library: [libdl.so]
0x00000001 (NEEDED) Shared library:
[C:\Users\build\Android\ci\jni\libBroken.so]
$


Potential problems: before API 23 the DT_NEEDED entry’s basename was used, but
starting from API 23 the Android runtime will try to load the library using the path
specified, and that path won’t exist on the device. There are broken third-party
toolchains/build systems that use a path on a build host instead of the SONAME.



Resolution: make sure all required libraries are referenced by SONAME only. It
is better to let the runtime linker to find and load those libraries as the
location may change from device to device.


Missing SONAME (Used since API 23)



Each ELF shared object (“native library”) must have a SONAME (Shared Object
Name) attribute. The NDK toolchain adds this attribute by default, so its
absence indicates either a misconfigured alternative toolchain or a
misconfiguration in your build system. A missing SONAME may lead to runtime
issues such as the wrong library being loaded: the filename is used instead when
this attribute is missing.



$ readelf --dynamic libWithSoName.so | grep SONAME
0x0000000e (SONAME) Library soname: [libWithSoName.so]
$


Potential problems: namespace conflicts may lead to the wrong library being
loaded at runtime, which leads to crashes when required symbols are not found,
or you try to use an ABI-incompatible library that isn’t the library you were
expecting.



Resolution: the current NDK generates the correct SONAME by default. Ensure
you’re using the current NDK and that you haven’t configured your build system
to generate incorrect SONAME entries (using the -soname linker
option).



Please remember, clean, cross-platform code built with a current NDK should have
no issues on Android N. We encourage you to revise your native code build so
that it produces correct binaries.