Ferdian Thung
email: ferdianthung@smu.edu.sg

Stefanus A Haryono
email: stefanusah@smu.edu.sg

Lucas Serrano
email: lucas.serrano@lip6.fr

Gilles Muller
email: gilles.muller@inria.fr

Julia Lawall
email: julia.lawall@inria.fr

David Lo
email: davidlo@smu.edu.sg

Lingxiao Jiang
email: lxjiang@smu.edu.sg

Automated Deprecated-API Usage Update for Android Apps: How Far Are We?

Keywords: API usage, program transformation, Android, mobile apps

As the Android API evolves, some API methods may be deprecated, to be eventually removed. App developers face the challenge of keeping their apps up-to-date, to ensure that the apps work in both older and newer Android versions. Currently, AppEvolve is the state-of-the-art approach to automate such updates, and it has been shown to be quite effective. Still, the number of experiments reported is moderate, involving only API usage updates in 41 usage locations. In this work, we replicate the evaluation of AppEvolve and assess whether its effectiveness is generalizable. Given the set of APIs on which AppEvolve has been evaluated, we test AppEvolve on other mobile apps that use the same APIs. Our experiments show that AppEvolve fails to generate applicable updates for 81% of our dataset, even though the relevant knowledge for correct API updates is available in the examples. We first categorize the limitations of AppEvolve that lead to these failures. We then propose a mitigation strategy that solves 86% of these failures by a simple refactoring of the app code to better resemble the code in the examples. The refactoring usually involves assigning the target API method invocation and the arguments of the target API method into variables. Indeed, we have also seen such transformations in the dataset distributed with the AppEvolve replication package, as compared to the original source code from which this dataset is derived. Based on these findings, we propose some promising future directions.

I. INTRODUCTION

In recent years, each release of Android has seen the deprecation of some APIs and the introduction of new ones. Due to the fragmentation of the Android market [START_REF] He | Understanding and detecting evolution-induced compatibility issues in Android apps[END_REF], [START_REF] Li | Cid: Automating the detection of API-related compatibility issues in Android apps[END_REF], app developers must update their apps to use the new APIs, while maintaining backward compatibility. Unfortunately, updating API uses is not always trivial. While API changes are described in the documentation, these descriptions are not always accompanied by concrete examples. When an API is used at many places in the app source code, updating its uses is tedious and error prone.

AppEvolve was recently proposed by Fazzini et al. [START_REF] Fazzini | Automated API-usage update for Android apps[END_REF] to automate the updating of Android apps in response to deprecations of Android APIs. The main idea of AppEvolve is that many software projects may use the APIs in similar ways, and thus existing codebases may already contain examples of how to update uses of deprecated APIs. Given a target app that uses a deprecated API and information about the new API method(s) that should replace it, AppEvolve collects update examples from existing codebases, abstracts their variable references, ranks them according to their expected applicability, and then tries to apply the abstracted examples one by one to the target app. If an abstracted example matches the code, the update is said to be applicable. Applicable updates are furthermore validated by testing. A key feature of AppEvolve is that it does not merge the abstracted examples into a single generic pattern, to avoid losing information that may be specific to particular usage contexts.

AppEvolve has been evaluated on a dataset involving 15 real-world apps and 20 real API changes. The dataset contains 41 usage locations of these real API changes. AppEvolve successfully produced validated applicable updates for 85% of these API changes and 90% of their usage locations. The paper on AppEvolve is accompanied by a replication package, containing the tool and the dataset. 1 We have reproduced the results of AppEvolve on this dataset.

In this work, our goal is to understand the generalizability of the results reported for AppEvolve, and to analyze the characteristics of the apps for which AppEvolve cannot generate applicable updates. To this end, we consider the same APIs and change examples as used in the AppEvolve evaluation, but create a new dataset of target apps. In selecting the new target apps, we make no effort to take the expected strengths or weaknesses of AppEvolve into account, and only check that the apps use one of the deprecated APIs considered in the AppEvolve dataset and do not use the corresponding replacement API. Of the apps we found at GitHub that satisfy these properties, we randomly selected 54 mobile apps that are entirely distinct from the original data set, and that involve 14 of the 20 real API changes and 54 usage locations.

We applied AppEvolve to update the deprecated-API usages in these mobile apps and analyzed the cases where it fails to update the apps. Indeed, running AppEvolve on our dataset generates applicable updates for only 10 out of 54 usage locations. It generates only failed updates, i.e., updates that do not match the deprecated-API invocation, for the remaining 44 usage locations. Our analysis shows that AppEvolve produces applicable updates for a mobile app in cases where the API usage closely matches an API change example. On the other hand, AppEvolve often fails to update a mobile app when there are minor syntactical differences between the invocations of the deprecated API in the target app and the change example. It also fails when there are semantic differences, such as the use of inheritance or the use of static or final modifiers, when encountering edits that require modifications beyond method boundaries, and when finding no relevant change examples in GitHub. Of these limitations, only the latter two were mentioned in the AppEvolve paper.

To try to understand the issues leading to the drastic performance difference as compared to the results of the original AppEvolve evaluation, we refactor the use of the deprecated in the target app code so that it more closely resembles the uses found in the change examples from which AppEvolve learns the edits. After refactoring, we found that AppEvolve can generate applicable updates for 86% of the cases where it previously failed to do so. Based on these results, we propose to mitigate the dependence of AppEvolve on the code structure of the examples and the deprecated API usage by normalizing the code to a standard form coupled with the use of identifiername recommendation, to improve existing work on automated deprecated-API usage updates for Android apps.

The main contributions of this paper are as follows:

• We evaluate AppEvolve with additional Android apps to investigate if it can effectively perform API-usage updates in different situations. The dataset that we created contains three times more real-world apps than those used to evaluate AppEvolve in the original paper (54 vs 15). • We categorize the limitations of AppEvolve and show API usage instances that are affected by these limitations. • We discuss how the limitations may be overcome to improve the automatic API-usage updates for Android apps.

• We release a replication package to allow easy replication and evaluation of our experiments and results. 2 The remainder of this paper is structured as follows. Section II describes AppEvolve, the state-of-the-art work on automated updates of deprecated API usages in Android apps. Section III presents our replication settings. Section IV presents our findings. Section V presents our mitigation strategy and results for some failed updates of Android apps. Section VI discusses limitations and threats to validity of our findings. Section VII presents related work. Finally, Section VIII concludes and presents promising future work.

II. APPEVOLVE

We describe the problem statement, the approach, the dataset, and the main experimental results of AppEvolve.

A. Problem Statement

AppEvolve targets the case where a set of one or more API methods of the Android framework are deprecated and 2 https://sites.google.com/smu.edu.sg/appevolve-replication replaced by another set of one or more API methods in a new version of the framework, and where the Android apps that use the old APIs need to be updated. The goal of AppEvolve is to automatically update such Android apps so that they use the new APIs, while maintaining backward compatibility.

As an example, in Android API version 23, the method getCurrentHour(), that had been present in the Android API since version 1, was deprecated and the method getHour() was suggested as its replacement. Figure 1 shows an example that modifies, among other changes, a usage of the method getCurrentHour() to its replacement method getHour(). Given this example and the mapping getCurrentHour → getHour, AppEvolve learns a generic patch for getCurrentHour() as shown in Figure 2. The generic patch updates a deprecated method getCurrentHour usage to a replacement method getHour usage. I and M mean that the corresponding piece of code are inserted and modified, respectively. Backward compatibility is achieved by checking the version number of the mobile OS running the app. If the version is greater than or equal to a certain version number, the replacement method is used. Otherwise, the deprecated method is used.

Note that AppEvolve can only perform API usage learning and update one mapping at a time. Thus, even though getCurrentMinute is also a deprecated method, App-Evolve does not learn how to update it since this case is the mapping getCurrentHour → getHour.

B. Approach

AppEvolve takes as input a target app to update and a mapping from deprecated API method(s) to the corresponding replacement API method(s). Its processing is divided into four phases: API-Usage Analysis, Update Example Search, Update Example Analysis and API-Usage Update, as shown in Figure 3, a simplified version we recreated according to the Figure 1 in the AppEvolve paper [START_REF] Fazzini | Automated API-usage update for Android apps[END_REF].

In the API-Usage Analysis phase, AppEvolve accepts as input an API Usage Change and a Target App. An API Usage Change describes the mapping from the deprecated API method(s) to the corresponding replacement API method(s). Information about this API usage change may come, for example, from the documentation of the API itself. A Target App is an app that contains a usage of the deprecated API method and requires updates to make use of the replacement API method. Given these two inputs, AppEvolve pinpoints the location of the deprecated API usage in the target app. In the Update Example Search phase, AppEvolve searches GitHub for examples of API usage updates that modify the usage of the deprecated API method to include the usage of the replacement API methods. In the Update Example Analysis phase, AppEvolve generates generic patches from the examples of API usage updates and ranks these patches. In the API Usage Update phase, AppEvolve tries to apply the ranked patches one by one and returns the Evolved Target App if any of the edits is successful and validated.

We next describe each of the above phases in detail. 1) API-Usage Analysis: AppEvolve finds the location where the deprecated API method specified in the API Usage Change is used inside the Target App. Consider the deprecated API method getCurrentHour() mentioned in Section II-A. In this case, the API Usage Change is the replacement of getCurrentHour() with getHour(). Given this information, AppEvolve finds the location in the Target App that invokes getCurrentHour().

2) Update Example Search: AppEvolve searches for apps in GitHub that use both the deprecated and the replacement API methods in their latest versions. For each such app, AppEvolve looks through the app history to find the commit where the uses of the replacement API methods are added. This is intended to find examples that produce a backward compatible Android app. For each of these apps, AppEvolve finds the changes that add the replacement API method to the app code that already contains the deprecated API method. These changes are the examples that can be used to update deprecated API method usages in other apps.

3) Update Example Analysis: Given the examples found in GitHub, AppEvolve translates each example to a generic patch. It does so by identifying edits related to the API usage via intraprocedural forward and backward dependency analysis on the variables involved in the API usage. Variables that are used in statements affected by the edits but not defined by the edits themselves are considered as context variables. All variables in the edits are then abstracted. Given the generic patches, AppEvolve computes the common core of these generic patches, defined as the longest subsequence of edits that are shared across the patches. The generic patches are then ranked based on their distance to the core.

4) API-Usage Update: Given a Target App, AppEvolve applies the generic patches according to their rank computed in the previous phase. When applying a patch, AppEvolve first finds mappings of the context variables to variables in the Target App. For each such mapping, AppEvolve then tries to apply the patch. If the edits are successfully applied, AppEvolve returns the Evolved Target App.

C. Experiments

For the target apps, the AppEvolve paper used 15 real-world apps from the F-droid repository. 3 These apps comprise five apps for each of Android API versions 22, 23, and 25, and cover 20 APIs used in 41 locations. For each API version, the API change is manually identified by reading the API documentation. Using the API change, the API usage in each app is guaranteed to be: (1) different from the ones in the other apps and (2) updated in the subsequent API version. When applied to the 15 apps considered, AppEvolve was able to update 17 out of 20 API usages (85% success rate) and 37 out of 41 (90% success rate) of their occurrences across the apps.

III. REPLICATION SETTINGS

The goal of our replication study is to determine whether the observed effectiveness of AppEvolve generalizes to a wider range of apps.

A. Dataset

Our replication study focuses on the same set of deprecated API methods as the original evaluation of AppEvolve and relies on the same set of change examples, but considers a different and larger set of mobile apps that use these deprecated methods. We find the mobile apps for our dataset by querying GitHub Code Search4 using the names of the APIs. GitHub Code Search returns a list of ranked files matching the query. Since Github Code Search only supports textual queries, it returns many false positives, i.e., files that do not actually use the API methods that were queried for. Thus, we manually check that the considered files contain usages of the desired deprecated APIs. We additionally check that the considered files do not use the replacement APIs. From the files that pass these checks, we randomly select 54 API usages, each from a different app, as our dataset.

We note that although the AppEvolve change examples also come from GitHub, there is no overlap with our dataset.

GitHub Code Search only indexes the latest version of each repository. The AppEvolve change examples consist of apps

where the latest version uses the replacement API, while our dataset consists of apps that do not use the replacement API. Thus, no overlap is possible.

B. Procedure

For each app in our dataset, we must create an AppEvolve configuration. To do so, we first carefully studied the configurations that were used in the original AppEvolve experiments. We also asked the first author of AppEvolve to confirm how to configure AppEvolve correctly. Finally, we ran our experiments in the virtual machine environment provided by the AppEvolve authors. 5After configuring AppEvolve for the apps, we ran App-Evolve on them. We recorded the number of applicable and failed updates. We then categorized the failed updates using card sorting [START_REF] Spencer | Card Sorting: Designing Usable Categories[END_REF]. For the first two authors performed multiple passes on the failed updates. In the first pass, they put each of the failed updates into a category created based on our understanding of the reason for the failure. In the subsequent passes, they reevaluated the categories. They might rename a category to be more descriptive of the problem that occurs in the set of updates belonging to the category, or merge related categories into one. If there was any disagreement, they discuss among themselves to resolve it. These steps were repeated until there were no more changes to the categories.

IV. FINDINGS

On our dataset, AppEvolve produces 10 applicable updates and 44 failed updates (19% success rate). The original AppEvolve evaluation also showed 4 failed updates. After investigating the 48 failed updates, we found some common reasons for the failures, as described below. Table I shows the number of occurrences of each of these issues.

1) The statements in the examples and at the target location are structurally different. AppEvolve infers edit operations at the statement level (insert a statement, move a statement, etc). Accordingly, AppEvolve is not able to apply changes inferred about method uses found in one kind of statement to a method use found in another kind of statement. We have observed that in the examples used in the evaluation of AppEvolve, it often occurs that the invocation of the deprecated API method is used as the right hand side of an assignment, while in our dataset the API method invocations occur in a variety of expression contexts. We now present some examples: 2) Object and arguments of the deprecated API method are complex expressions. In creating edits, AppEvolve only abstracts over variables. Accordingly, when examples always contain variables for the object or the arguments, the generated edits are not sufficient to update code in which these subterms are expressed as more complex expressions.

In the code shown on the left side of Listing 6 in Table II, an invocation of the deprecated method setTextAppearance involves expressions that do not have the form of a simple variable for both the object and arguments.

3) Edits beyond method boundaries. AppEvolve cannot learn edits that modify program elements that reside outside of the method containing the API usage to be updated. These edits include operations such as adding imports and adding fields to a class. Below is a snippet of an update example that involves edits beyond method boundaries. The above example involves a use of the deprecated API addGpsStatusListener. Updating a use of this API requires adding a private field callback of type GnssStatus.Callback. Since AppEvolve only learns edits inside a method containing the deprecated API usage, it misses this necessary addition. In the AppEvolve paper, this category is described as missing context information. 4) Specific programming language features. AppEvolve fails to update cases in which the update involves programming language features such as:

• Static modifier: The code on the left hand side of Listing 7 in Table III shows an example of this case. The deprecated API method requestAudioFocus is invoked by mAudioManager, which is a static field. • Final modifier: The code in the left hand side of Listing 8 in Table III shows an example of this case. Variable paint that is used as the fourth argument to the deprecated API method saveLayer is a final field. The categories edits beyond method boundaries and no examples are from target apps in the original AppEvolve dataset and these categories are reported in the AppEvolve paper. The other categories are uncovered from our dataset.

V. MITIGATIONS

To mitigate the observed failures, we tried to modify the deprecated API usages in the target app's source code so that AppEvolve could produce an applicable update. Looking at the 10 apps that were updated successfully, we observe that in each case the invocation of the deprecated method appears as the right-hand side of an assignment statement, or any arguments of the deprecated method are simple variables. We transform the remaining apps where possible accordingly, converting the invocations of the deprecated APIs to a form reminiscent of the three address code used in compiler intermediate representations [START_REF] Aho | Compilers, principles, techniques, and tools[END_REF].

In essence, our mitigations refactor the deprecated method invocation in the target app to resemble the examples from which AppEvolve learns edits. The right side of Table II shows a diff that applies these mitigations on the cases presented in Section IV where the mitigation allows AppEvolve to produce applicable updates. 1) After the refactoring described in Listing 1 Table II, rather than directly returning the result of invoking the deprecated method fromHtml, we first assign it to a fresh variable named a of type Spanned. 2) After the refactoring described in Listing 2 of Table II, rather than directly inserting the constants AudioManager.STREAM_MUSIC and AudioManager.AUDIOFOCUS_GAIN as the second and third arguments of requestAudioFocus, we first assign them to fresh int-typed variables arg1 and arg2, respectively. Moreover, the result of invoking requestAudioFocus is assigned to a fresh variable named res of type AudioManager that is then used in the if condition. 3) After the refactoring described in Listing 3 of Table II, rather than directly inserting the result of invoking getCurrentHour as the second argument of String.format, the result is first assigned to fresh a variable named hour of type int. 4) After the refactoring described in Listing 4 of Table II, rather than concatenating the result of getCurrentHour directly to ":", the result is first assigned to a fresh variable named hour of type int. 5) After the refactoring described in Listing 5 of Table II, rather than directly assigning the result of invoking getCurrentHour to the variable hours when it is declared, we declare hours first and then assign the result of invoking getCurrentHour to hours. 6) After the refactoring described in Listing 6 of Table II, rather than invoking setTextAppearance directly from the object returned by invoking findViewById, the returned object is first assigned to a variable named t of type TextView. setTextAppearance is then invoked from t. Our mitigations result in 38 successful updates out of the 44 failed updates on the apps in our dataset (86% success rate), overall giving success on 48 out of the 54 apps in our dataset (89% success rate).

VI. DISCUSSION

In this section, we discuss the relation of our results to those originally presented for AppEvolve, future directions for improving the approach to updating deprecated API usage in Android apps, and threats to validity.

A. Result Assessment

We were initially surprised by the large difference between the results on our data set, where we obtained a success rate of 19%, and the results reported by the authors of AppEvolve, who obtained a success rate of 85%, even though our dataset was constructed randomly, without taking into account the strengths or weaknesses of AppEvolve. Indeed, given that AppEvolve relies on matching statements, abstracting only over variables, it is surprising that AppEvolve could achieve such high accuracy on e.g. simple getter methods such as getCurrentHour() (e.g., Listing 3). In our dataset, such methods are often used as subexpressions of arbitrarily complex statements, which may contain project-specific code.

Likewise, as illustrated by Listing 2, invocations of method calls may have arbitrarily complex, possibly project-specific, arguments that are not likely to be found in other codebases.

To understand better how AppEvolve is able to achieve a high rate of success in the previously reported evaluation, we investigate the examples and target apps used. Given the difficulty of finding the original files for the examples, for which no origin information is provided, we focus on a single example, the call to getCurrentHour() in the app CONVERSATIONS version 1.8.0 in F-Droid (A02-U03 in the AppEvolve paper). In F-Droid, we find that the only invocation of getCurrentHour() occurs in the argument list of a call to the set method of the Calendar class, a code structure similar to the code shown on the left side of Listing 3. In the AppEvolve dataset, this call is extracted into a separate statement, analogous to our mitigation shown on the right side of Listing 3. We have furthermore looked at one of the examples provided for this API, and have found the original code on GitHub in the file RepeaterDialogFragment.java from the marekpiotrowskimp/nyndro_remote repository. Again, we find that in the GitHub code, the call appears in an argument list, while the corresponding example in the AppEvolve example set has been transformed analogous to our mitigation. These changes convert invocations that occur in differing contexts to invocations that can be exploited by AppEvolve.

We note that the observed issue appears to be a direct result of the key design decision of AppEvolve, of not merging examples. Merging could motivate discarding irrelevant context of the use of the deprecated method and extending the abstraction of subterms beyond variables, but, as observed by the authors of AppEvolve, it could discard some information that is necessary to correctly perform the transformation.

B. Future Directions

Code Normalization. Our above analysis suggests that our mitigation succeeds because the AppEvolve authors have already performed such a mitigation in the change examples included in the AppEvolve replication package. To improve the results of AppEvolve in the more general case, a solution could be to systematically first normalize the change examples to a standard form. Edits can then be learned from this standard form. When the edit is applied to a new piece of code, that target code should also be normalized, to minimize the code variations. If the edits are successfully applied, the resulting code can then be refactored again to restore the coding style of the developers. Our mitigations represent a subset of the normalizations that may be possible.

Coding Style and Readability. Any tool that automatically transforms code runs the risk of converting the code to a style that is incompatible with the preferences of the given app's developers. In the case of AppEvolve, there is already the risk of changing the existing coding style to the coding style found in the app providing the change example, and any normalization performed to the target code further increases this risk. To assess the impact of AppEvolve on coding style, we perform a simple experiment to compare the output of AppEvolve after applying our mitigation with code that is manually updated to deal with a set of deprecated APIs. We asked a software engineer who is not an author of this paper to update the code shown on the left hand side of Listing 4 in Table II Semantic Preservation. The code made manually by the engineer is substantially different from the code produced by AppEvolve, and developers may indeed prefer the code made by the engineer. In particular, the engineer did not introduce fresh variables and provide a more concise code. Future work may investigate how to restore the original coding style after applying AppEvolve. One step would be to choose good names for the newly introduced variables. Some recent studies use deep learning and mining software repositories to recommend method and class names [START_REF] Allamanis | Suggesting accurate method and class names[END_REF]. These approaches can potentially be extended for inferring good variable names in our context.

C. Threats to Validity

One threat is related to whether we have configured App-Evolve correctly. To mitigate this threat, we have tried our best to run AppEvolve following the instructions given by the authors in the AppEvolve documentation. We have also asked AppEvolve's first author how to configure AppEvolve correctly for new mobile apps. Based on the information obtained, we independently reconstructed the configurations for the target apps in the original dataset, and using these configurations were able to reproduce the results reported for that dataset. We have also rechecked our configurations for the new dataset several times. We have released a replication package for others to check and validate. 6Another threat is related to the generalizability of the findings. We have added 54 new applications to evaluate the effectiveness of AppEvolve in generating applicable updates. This translates to 54 API usage locations on top of the 41 API usage locations in AppEvolve dataset, thus more than doubling the number of API usage locations and more than tripling the number of apps as compared to the dataset used in the original work. We believe this is sufficient to understand the capabilities of AppEvolve, as 44 of the 54 API usages that we have added uncover limitations of AppEvolve. There might be other cases that AppEvolve cannot handle, but we believe that we have found many of them.

VII. RELATED WORK A. API Deprecation

Many works have studied API deprecation. Zhou and Walker [START_REF] Zhou | API deprecation: a retrospective analysis and detection method for code examples on the web[END_REF] found that, in practice, deprecating APIs does not always follow deprecated-replace-remove cycle, such as many deprecated APIs are undeprecated. They also developed a tool to warn about deprecated API usages in StackOverflow posts. Kapur et al. [START_REF] Kapur | Refactoring references for library migration[END_REF] found that APIs might be removed without being marked as deprecated. Raemaekers et al. [START_REF] Raemaekers | Semantic versioning versus breaking changes: A study of the maven repository[END_REF] discovered that some Java artifacts on the Maven Central Repository never remove deprecated APIs. Brito et al. [START_REF] Brito | Do developers deprecate APIs with replacement messages? a large-scale analysis on Java systems[END_REF] showed that not all APIs are annotated with replacement messages. Robbes et al. [START_REF] Robbes | How do developers react to API deprecation?: the case of a smalltalk ecosystem[END_REF] analyzed the Smalltalk ecosystem and showed that some API changes caused by deprecation can substantially impact the ecosystem. This study was replicated on the Java ecosystem and similar results were reported [START_REF] Anand | On the reaction to deprecation of 25,357 clients of 4+ 1 popular Java APIs[END_REF], [START_REF] Anand | On the reaction to deprecation of clients of 4+ 1 popular Java APIs and the JDK[END_REF], except that the number of deprecated API replacements was higher in the Smalltalk ecosystem. Sawant et al. [START_REF] Ashok Sawant | Why are features deprecated? an investigation into the motivation behind deprecation[END_REF] created a taxonomy containing 12 reasons for deprecation and developed an approach to automatically classify them. Li et al. [START_REF] Li | Characterising deprecated Android APIs[END_REF] performed an exploratory study on characterizing Android APIs. They found that, among other things, deprecated Android APIs are not always consistently annotated and documented, and they are also regularly cleaned up.

API deprecation may introduce compatibility issues. Some work suggest fixes for these compatibility issues [START_REF] Huang | Understanding and detecting callback compatibility issues for android applications[END_REF], [START_REF] Scalabrino | Data-driven solutions to detect api compatibility issues in android: an empirical study[END_REF], [START_REF] Wei | Taming android fragmentation: Characterizing and detecting compatibility issues for android apps[END_REF]. Wei et al. [START_REF] Wei | Taming android fragmentation: Characterizing and detecting compatibility issues for android apps[END_REF] proposed FicFinder to detect compatibility issues in Android apps by capturing pairs of APIs and their context that triggers the issues. Huang et al. [START_REF] Huang | Understanding and detecting callback compatibility issues for android applications[END_REF] proposed Cider to detect callback compatibility issues in Android apps. Scalabrino et al. [START_REF] Scalabrino | Data-driven solutions to detect api compatibility issues in android: an empirical study[END_REF] proposed CiD to detect compatibility issues in Android APIs by analyzing the changes in the history of Android APIs.

All of the above studies aim to understand API deprecation. In this work, we aim to understand the applicability of a stateof-the-art approach for automatic update of Android apps, which updates usages of deprecated methods to corresponding usages of their replacement methods.

B. Replication Studies

There have been a number of replication studies in the software engineering domain that have provided new insights about the replicated studies. Chen and Jiang [START_REF] Chen | Characterizing logging practices in Java-based open source software projects -a replication study in apache software foundation[END_REF] replicated a study by Yuan et al. [START_REF] Yuan | Characterizing logging practices in open-source software[END_REF] of logging practices. In contrast to the observations of Yuan et al., Chen and Jiang found that bug reports without a log message take a shorter time to resolve than bug reports that include a log. Greiler et al. [START_REF] Greiler | Code ownership and software quality: A replication study[END_REF] replicated the work of Bird et al. [START_REF] Bird | Don't touch my code!: Examining the effects of ownership on software quality[END_REF] on the correlation between code ownership and software quality. Greiler et al. used new and refined code ownership metrics and prediction models. Akbarinasaji et al. [START_REF] Akbarinasaji | Predicting bugfixing time[END_REF] replicated and reinforced the finding on the bug fixing time estimation model by showing similar result with the previous work. A replication study on open source development by Trong et al. [START_REF] Trung | The freebsd project: A replication case study of open source development[END_REF] found new findings from the previous work by Mockus et al. [START_REF] Mockus | Two case studies of open source software development: Apache and mozilla[END_REF]. They supported some of the previous hypotheses and proposed revisions on hypothesis related to the need of formal arrangement for work coordination and on hypothesis regarding the number of core developers on open source project. A replication study by Orru et al. [START_REF] Orrù | How do Python programs use inheritance? a replication study[END_REF] conducted an analysis of the use of inheritance in Python systems that was previously done on Java. Their result shows that compared on the previous findings on Java, Python has more classes that are inherited from but fewer classes that inherit from other classes. Our replication study highlights unreported limitations of the studied tool.

C. Program Transformation

Normalization of code to improve the results of program transformations has a long history. It was extensively used in the early 1990s in the context of partial evaluation (specialization of programs to the values of some known inputs), in the form of binding-time improvements, in order to bring known values closer together, to allow code simplifications [START_REF] Jones | Partial Evaluation and Automatic Program Generation[END_REF]. Namjoshi and Pavlinovic have more generally studied and formalized the impact of program transformations on program analysis [START_REF] Kedar | The impact of program transformations on static program analysis[END_REF], considering both positive and negative impacts on precision.

AppEvolve is part of a line of research that has recently been attracting increasing interest on inferring program transformations from one or more examples. Some that could potentially benefit from our mitigation include LASE [START_REF] Meng | Lase: Locating and applying systematic edits by learning from examples[END_REF] and REFAZER [START_REF] Rolim | Learning syntactic program transformations from examples[END_REF]. LASE [START_REF] Meng | Lase: Locating and applying systematic edits by learning from examples[END_REF] creates an edit script from common changes in a set of examples, locates the edit locations in a target application, and does the code transformation automatically. However, LASE is only able to abstract variable, method and type names, and thus it will never consider a method invocation with a simple variable as an argument to be the same as a method invocation where the argument is a more complex expression. Thus, it could potentially benefit from our mitigation. REFAZER [START_REF] Rolim | Learning syntactic program transformations from examples[END_REF] learns rewrite rules from change examples provided by the user. Rewrite rules use some information about the change context to determine whether a rule should be applied, which can limit rule applicability when a deprecated API is used in different contexts. Applying our mitigation to the context could reduce the diversity and increase the rule applicability. Some other transformationrule inference systems, such as PHOENIX [START_REF] Bavishi | Phoenix: Automated data-driven synthesis of repairs for static analysis violations[END_REF], Spdiff [START_REF] Andersen | Semantic patch inference[END_REF], and REVISAR [START_REF] Rolim | Learning quick fixes from code repositories[END_REF] can describe terms appearing in arbitrary contexts and containing arbitrary subexpressions, and may thus benefit less or not at all from our mitigation.

VIII. CONCLUSION AND FUTURE WORK

AppEvolve is the state-of-the-art approach for automatic update of deprecated-API usage in Android apps. Experiments previously reported for AppEvolve have shown that it can generate applicable updates for 85% of these API changes and 90% of their usage locations on mobile apps in the AppEvolve dataset.

In this work, we evaluate whether this observed effectiveness is generalizable. We add 54 additional mobile apps that use the APIs contained in the AppEvolve dataset. Running AppEvolve on these mobile apps shows that AppEvolve fails to generate applicable updates for 81% of the mobile apps. By analyzing these failed cases, we found that they failed mainly due to:

1) Statements in the examples and at the target location are structurally different. 2) Object and arguments of the deprecated API method are in the form of complex expressions. 3) Edits are required beyond method boundaries. 4) Specific programming language features.

5) No examples found in GitHub.

We mitigate the first and the second categories by performing a simple refactoring that modifies the code containing API usage in the target app to resemble the one in the example. Our mitigations enable AppEvolve to generate applicable updates for 86% of the failed cases.

To try to resolve the discrepancy in the findings, we looked closer at the examples and target apps used by finding the original examples and target apps. We found that they were transformed analogous to our mitigation. These transformations convert invocations in various contexts into code exploitable by AppEvolve.

Based on our findings, we propose future directions for automatic update of deprecated-API usage in Android apps, which include code normalization to ensure that both the example of API usage and the target app code are in the same standard form to minimize the variety of ways that the code is written. Using this technique, simple refactoring that we use to mitigate the failed cases may not be necessary. We also propose the usage of identifier name recommendation to name new variables that may have been introduced due to code normalization.

Fig. 2 .

 2 Fig. 1. A deprecated API-usage update

Fig. 3 .

 3 Fig. 3. Framework of AppEvolve

TABLE I UPDATE

 I FINDINGS STATISTICS (SOME OCCURRENCES OF DEPRECATED APIS ARE IN MULTIPLE CATEGORIES)

	Category	Subcategory	Occurrences
		Return statement	6
	Statements in the examples	If statement	1
	and at the target location are	Method argument	4
	structurally different	Arithmetic operand	3
		Declared variable	12
	Object and arguments of the	-	20
	deprecated API method are
	in the form of complex
	expressions
	Edits beyond method bound-	-	3
	aries
	Specific	Inheritance	2
	programming-language	Static modifier	1
	features	Final modifier	1
	No examples	-	1
	Others	-	4

•

  Return statement (left side of Listing 1 in Table II): An invocation of the deprecated method fromHtml appears as part of a return statement of the getTitle method. • If statement test (left side of Listing 2 in Table II): An invocation of the deprecated method requestAudio-Focus appears as a subexpression of the test expression of a conditional. • Method argument (left side of Listing 3 in Table II): An invocation of the deprecated method getCurrentHour appears as the second argument of the invocation of method String.format.

• Binary operator (left side of Listing 4 in Table

II

): An invocation of the deprecated method getCurrentHour appears as the left argument of a concatenation with ":".

• Declared variable (left side of Listing 5 in Table

II

): An invocation of the deprecated method getCurrentHour appears as the initial value of a declared variable. Even though this case involves an assignment, such code does not match examples where the assignment involves a previously declared variable.

18a19 + import android.location.GnssStatus; 22a24 + import android.os.Build; 33a36,37 + private GnssStatus.Callback callback; 41c45,51 -locationManager.addGpsStatusListener(listener); + if (android.os.Build.VERSION.SDK_INT >=

		android.os.Build.VERSION_CODES.N) {
	+	locationManager.registerGnssStatusCallback(callback);
	+ }
	+ else{
	+	locationManager.addGpsStatusListener(listener);
	+ }

public class TestMediaPlayer extends MediaPlayer { public TestMediaPlayer() { setAudioStreamType(AudioManager.STREAM_MUSIC); } public TestMediaPlayer(Context testContext

	,
	int withResource) throws Exception {
	this();
	AssetFileDescriptor afd = testContext.getResources()
	.openRawResourceFd(withResource);
	assertNotNull(afd);
	setDataSource(afd.getFileDescriptor(),
	afd.getStartOffset(),afd.getLength());
	afd.close();
	prepare();
	}
	}
	5) No examples. No example illustrating the API update can
	be found in GitHub.
	6) Others. These include cases that cannot be put to any
	category above.

• Inheritance: The code below uses the deprecated API method setAudioStreamType of the class MediaPlayer. In the code snippet, TestMedia-Player extends MediaPlayer and thus it inherits the setAudioStreamType method. This method should be updated but AppEvolve does not seem to recognize it due to the use of inheritance.

TABLE III SUCCESSFUL

 III SIMPLE REFACTORING MITIGATIONS THAT ALLOW APPEVOLVE TO GENERATE APPLICABLE UPDATES (PART II)

	Listing	Original Code	Refactoring Diff
	7. Incomplete	private static AudioManager mAudioManager;	private static AudioManager mAudioManager;
	support: static	private static OnAudioFocusChangeListener	private static OnAudioFocusChangeListener
		afChangeListener;		afChangeListener;
		public static void requestAudioFocus	public static void requestAudioFocus
		(Context context) {	(Context context) {
		if(mAudioManager == null){	if(mAudioManager == null){
		mAudioManager = (AudioManager)		mAudioManager = (AudioManager)
		context.getApplicationContext()		context.getApplicationContext()
		.getSystemService		.getSystemService
		(Context.AUDIO_SERVICE);		(Context.AUDIO_SERVICE);
		}	}
		mAudioManager.requestAudioFocus(	-mAudioManager.requestAudioFocus(
		afChangeListener,	-	afChangeListener,
		AudioManager.STREAM_MUSIC,	-	AudioManager.STREAM_MUSIC,
		AudioManager.AUDIOFOCUS_GAIN);	-	AudioManager.AUDIOFOCUS_GAIN);
		}	+ int res;
			+ int a = AudioManager.STREAM_MUSIC;
			+ int b = AudioManager.AUDIOFOCUS_GAIN;
			+ AudioManager am = mAudioManager;
			+ AudioManager.OnAudioFocusChangeListener
			+	af = afChangeListener;
			+ res = am.requestAudioFocus(af,a,b);
			}
	8. Incomplete	private final Paint paint;
	support: final	@Override protected void onDraw(Canvas canvas) {
		super.onDraw(canvas);
		canvas.drawColor(Color.GREEN);
		canvas.saveLayer(0, 0, canvas.getWidth(),
		canvas.getHeight(), paint,
		Canvas.ALL_SAVE_FLAG);
		canvas.restore();
		}

private final Paint paint; @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); canvas.drawColor(Color.GREEN); +

makeText(this, time, Toast.LENGTH_SHORT).show(); }

  . The code generated by AppEvolve and by the engineer is shown below.

	timePicker.getCurrentMinute();
	} else {
	time = timePicker.getCurrentHour() + ":" +
	timePicker.getCurrentMinute();
	}
	Toast.
	AppEvolve's Update
	public void displayTime(View view){
	int hour;
	if (android.os.Build.VERSION.SDK_INT >=
	android.os.Build.VERSION_CODES.M) {
	hour=timePicker.getHour();
	}
	else {
	hour=timePicker.getCurrentHour();
	}
	String time=hour + ":" + timePicker.getCurrentMinute();;
	Toast.makeText(this,time,Toast.LENGTH_SHORT).show();
	}
	Engineer's Update
	public void displayTime(View view) {
	String time;
	if (android.os.Build.VERSION.SDK_INT >= 23) {
	// only for marshmallow and newer versions
	time = timePicker.getHour() + ":" +

https://sites.google.com/view/appevolve

https://fdroid.org

https://github.com/search

https://sites.google.com/view/appevolve

https://sites.google.com/smu.edu.sg/appevolve-replication

ACKNOWLEDGEMENT

This research was supported by the Singapore National Research Foundation (award number: NRF2016-NRF-ANR003) and the ANR ITrans project.


Stefanus A Haryono
email: stefanusah@smu.edu.sg

Ferdian Thung
email: ferdianthung@smu.edu.sg

Jin Hong

Kang

Lucas Serrano
email: lucas.serrano@lip6.fr

Gilles Muller
email: gilles.muller@inria.fr

Julia Lawall
email: julia.lawall@inria.fr

David Lo
email: davidlo@smu.edu.sg

Lingxiao Jiang
email: lxjiang@smu.edu.sg

Automatic Android Deprecated-API Usage Update by Learning from Single Updated Example

Keywords: API update, program transformation, Android, single example

Due to the deprecation of APIs in the Android operating system, developers have to update usages of the APIs to ensure that their applications work for both the past and current versions of Android. Such updates may be widespread, non-trivial, and time-consuming. Therefore, automation of such updates will be of great benefit to developers. AppEvolve, which is the state-of-the-art tool for automating such updates, relies on having before-and after-update examples to learn from. In this work, we propose an approach named CocciEvolve that performs such updates using only a single after-update example. CocciEvolve learns edits by extracting the relevant update to a block of code from an after-update example. From preliminary experiments, we find that CocciEvolve can successfully perform 96 out of 112 updates, with a success rate of 85%.

INTRODUCTION

When an Android API is deprecated, apps using the API should update their usages of the API to ensure that they still work in the current and future versions of Android. For these updates, developers need to learn the new API(s) that should replace the deprecated API, while maintaining backward compatibility with older versions to address Android fragmentation [START_REF] He | Understanding and detecting evolution-induced compatibility issues in Android apps[END_REF][START_REF] Li | Cid: Automating the detection of API-related compatibility issues in Android apps[END_REF]. Moreover, the deprecated API may be used in multiple locations in a codebase. Thus, manually updating the deprecated API may be cumbersome and time consuming.

To help developers in updating usages of deprecated APIs with their replacement APIs, Fazzini et al. [START_REF] Fazzini | Automated API-usage update for Android apps[END_REF] proposed AppEvolve to automate the update task. AppEvolve learns to transform applications that use a deprecated API by learning from before-and after-update Permission to make digital or hard copies of all or part of this work for personal or classroom use is granted without fee provided that copies are not made or distributed for profit or commercial advantage and that copies bear this notice and the full citation on the first page. Copyrights for components of this work owned by others than ACM must be honored. Abstracting with credit is permitted. To copy otherwise, or republish, to post on servers or to redistribute to lists, requires prior specific permission and/or a fee. Request permissions from permissions@acm.org. ICPC '20, October 5-6, 2020, Seoul, Republic of Korea © 2020 Association for Computing Machinery. ACM ISBN 978- Recently, Thung et al. [START_REF] Thung | Automated Deprecated-API Usage Update for Android Apps: How Far Are We?[END_REF] reported that, in order for AppEvolve to perform a successful update, the target code requiring update has to be written syntactically similar to the before-and after-update example. They demonstrated that AppEvolve's performance can be improved significantly if the app code is manually rewritten to have syntactic similarities to the before-and after-update example.

In this work, we propose CocciEvolve. CocciEvolve outperforms AppEvolve in the following aspects:

(1) CocciEvolve eliminates the shortcoming of AppEvolve by normalizing both the after-update example and the target app code to update. In this way, CocciEvolve ensures that both of them are written similarly, thereby preventing unsuccessful updates caused by minor differences in the way the code is written. (2) CocciEvolve requires only a single after-update example for learning how to update an app that uses a deprecated API. Consider an after-update example in Figure 1. The if and else blocks correspond to the code using the replacement and deprecated API methods, respectively. The code in the if block runs only on versions of Android after the deprecation. Thus, the code in else block can be considered as the code that uses the deprecated method before the update. (3) Transformations made by CocciEvolve are expressed in the form of a semantic patch by leveraging Coccinelle [START_REF] Lawall | Coccinelle: 10 years of automated evolution in the Linux kernel[END_REF]. Semantic patch has a syntax similar to a diff that is familiar to software developers. Therefore, the modifications process are more readable and understandable to developers. The contributions of our work are: • We propose CocciEvolve, an approach for updating Android deprecated-API usages using only a single after-update example.

• We perform automatic code normalization of both the update example and the target code to be updated, addressing the challenge of updating code that is semantically equivalent but syntactically different, which was a limitation of prior work. • We have evaluated CocciEvolve with a dataset of 112 target files to update that we obtained from Github. The 112 files use 10 deprecated APIs used in the original evaluation of AppEvolve. We show that CocciEvolve can successfully update 96 target files. The remainder of this paper is structured as follows. Section 2 provides some preliminaries. Section 3 details our proposed approach. Section 4 describes our preliminary experiments and results. Section 5 presents related work. Finally, we conclude in Section 6.

PRELIMINARIES

AppEvolve. AppEvolve is the state-of-the-art tool automating APIusage updates for deprecated Android APIs. As input, it takes an app to update and a mapping from a deprecated method to its replacement method(s). It has four phases: API-Usage Analysis, Update Example Search, Update Example Analysis, and API-Usage Update.

In the API-Usage Analysis phase, AppEvolve finds uses of the deprecated method inside the app. In the Update Example Search phase, AppEvolve searches GitHub for apps that use both the deprecated and replacement methods in the same file. For each of these apps, AppEvolve searches the app commit history for a change that adds the replacement method(s) without removing the deprecated method. These changes are used to learn how to update deprecated method usages. In the Update Example Analysis phase, AppEvolve produces a generic patch from each example. AppEvolve then computes the common core from the produced generic patches. The common core is the longest subsequence of edits across the patches. In the API-Usage Update phase, AppEvolve applies generic patches in ascending order of their distance to the common core. To apply a generic patch, AppEvolve tries to match context variables to variables in the app. If matches are found, AppEvolve applies edits in the generic patch and returns the updated app if the edits are successful.

Coccinelle4J. Coccinelle4J [START_REF] Hong | Semantic Patches for Java Program Transformation (Experience Report)[END_REF] is a recent Java port of Coccinelle, which is a program matching and transformation tool [START_REF] Lawall | Coccinelle: 10 years of automated evolution in the Linux kernel[END_REF][START_REF] Padioleau | Documenting and automating collateral evolutions in Linux device drivers[END_REF]. Given the source code of a program and a semantic patch describing the desired transformations, Coccinelle4J transforms the parts of the source code that match the semantic patch.

Written in the Semantic Patch Language (SmPL), a semantic patch has two parts: (1) context information, including the declaration of metavariables; and (2) changes to be made to the source code. A metavariable can match program elements of the type indicated in its declaration. Modifications are expressed using fragments of Java as follows: (1) code that should be removed by annotating the start of the lines with -; and (2) code that should be added by annotating the start of the lines with +. Unannotated lines add context to the semantic patch. Figure 2 showed an example of a semantic patch. The line surrounded by @@ declares the metavariable.

APPROACH

An overview of our proposed system and the relevant pipelines are shown in Figure 3. CocciEvolve is built on three main components: (1) Source file normalization, (2) Updated API block detection, and @@ expression timepicker ; @@ -timepicker . getCurrentHour (); + timepicker . getHour (); (3) API-update semantic patch creation. These components are the building blocks of the CocciEvolve pipelines: a pipeline to create the update semantic patch, and a pipeline to apply the update to a target file. The create update patch pipeline takes as inputs the API usage change, and a source file containing updated API call. The apply update pipeline takes as inputs the API usage change, target source file, and the update semantic patch file. In the following subsections, we will explain in detail each of the system components.

Source File Normalization

Different software developers may have different programming styles, thus, semantically-equivalent code may be expressed in different syntactic forms. As a result, equivalent usages of one API may vary in its expression . Figure 4 shows an example of such cases in which getCurrentHour() is expressed differently. Therefore, it is necessary to perform source code normalization. Focusing on source code that is related to the API usage, we perform the following code normalization steps:

• An API call contained in a compound expression or statement (e.g. if, loop, return, etc) is extracted into a variable assignment. • Arguments of an API call are extracted into variable assignments.

• The object receiving an API call is extracted into a variable assignment. Two components are responsible for normalization in CocciEvolve:

Variable

Extractor. The Variable Extractor is used to extract the arguments and object that the API call is invoked on. These arguments and object are assigned to temporary variables. As before, this extraction is done through Coccinelle4J using a semantic patch. An example of this extraction is shown in Figure 6.

Updated API Block Extractor

The Updated API Block Extractor identifies the relevant block of code containing the updated API call. This block is extracted and used as the source of the update patch. In order to prevent false positives due to irrelevant code blocks, we use the following rules to identify a valid updated API block: (1) A valid updated block contains the updated API call in the if branch and the old API call in the else branch or vice versa. (2) A valid updated block will have an Android version check as the if condition. These classification rules are implemented in two components: 3.2.1 Version Statement Normalization. One of the important criteria for a valid updated block is the presence of an if statement that checks for the Android version. However, this check may take different forms in different projects (e.g. the Android version may first be assigned to a local variable). To alleviate this problem, Coc-ciEvolve normalizes the conditions involving the Android version. This normalization is done automatically by first detecting any assignment of an Android version constant to a variable, and then replacing usage of the local variable in a condition with the relevant Android version constant. An example can be seen in Figure 7.

API Update Semantic Patch Creation

Using the normalized update block as an input, this component creates a Coccinelle4J semantic patch that can be used to update a normalized target file. This component will replace variables and expressions with metavariables. Metavariables will bind to program elements in the input code passed into Coccinelle4J. The patch works by detecting the location of the old API call and then adding the new code which consists of a surrounding if block, the updated API call, and new variables introduced by the new API.

To increase the robustness of the system, for APIs that return a value, two different update rules are created. One rule is for cases where the return value is assigned into a variable, while the other is for cases where the return value is not used. An example of the update semantic patch can be seen in Figure 8.

EXPERIMENTS 4.1 Dataset

To assess the performance of CocciEvolve for practical usage, we use a dataset of real-world Android projects retrieved from public Github repositories. For this purpose, we use AUSearch [START_REF] Hilmi Asyrofi | AUSearch: Accurate API Usage Search in GitHub Repositories with Type Resolution[END_REF], a tool for searching Github repositories, to find Android API usage. For the update semantic patch creation, we use the existing after-update examples provided in the AppEvolve replication package. For each API, only a single after-update example is used. We obtained a total of 112 target source files from Github for the 10 most commonly used APIs that were used in the original evaluation of AppEvolve. These target files are disjoint from the target files used by AppEvolve and thus are used to evaluate AppEvolve's generalizability in updating other target files. Detailed statistics for this dataset can be seen in Table 1. This dataset is published with our replication package. 1

Experimental Settings

Our experiments are done by comparing the performance of Coc-ciEvolve against AppEvolve based on the number of applicable 1 https://sites.google.com/view/cocci-evolve/ The target files for the experiments are the public Android project dataset that have been collected from Github through the use of AUSearch [START_REF] Hilmi Asyrofi | AUSearch: Accurate API Usage Search in GitHub Repositories with Type Resolution[END_REF]. CocciEvolve is applied to every target file using the relevant API update patch that was created. For experiments involving AppEvolve, we need to configure each target project as an Eclipse project and create an additional XML file that contains the deprecated API description and their locations in the file. Due to this limitation, our experiments on AppEvolve are focused on first instance of each API call for each target project.

Results

In our experiments, CocciEvolve attains a better performance compared to AppEvolve. For most APIs, CocciEvolve achieves a near perfect result. We ask a software engineer with three years experience in Android, who was not part of this project, to validate the correctness of the update by verifying that there are no semantic changes in the update. Our experimental results are also included in our replication package.

In most cases, AppEvolve does not produce any code update. Thung et al. [START_REF] Thung | Automated Deprecated-API Usage Update for Android Apps: How Far Are We?[END_REF] note that AppEvolve requires some manual code refactoring and modifications to be able to perform the automated update. Table 2 shows the statistics of our evaluation.

Based on the experiments result, we can see that CocciEvolve mainly failed for two APIs: getAllNetworkInfo() and requestAu-dioFocus(...). Updating these two APIs requires the creation of new objects for arguments to the replacement APIs. These objects are frequently created outside of the updated API block, and will require a data flow analysis to detect and construct the update correctly. The current version of CocciEvolve does not support sophisticated data-flow analysis.

RELATED WORK

There are many studies on API deprecation [START_REF] Brito | Do developers deprecate APIs with replacement messages? A large-scale analysis on Java systems[END_REF][START_REF] Kapur | Refactoring References for Library Migration[END_REF][START_REF] Li | ELEGANT: Towards Effective Location of Fragmentation-Induced Compatibility Issues for Android Apps[END_REF][START_REF] Li | CiD: automating the detection of API-related compatibility issues in Android apps[END_REF][START_REF] Li | Characterising deprecated Android APIs[END_REF][START_REF] Ashok Sawant | Why are features deprecated? An investigation into the motivation behind deprecation[END_REF][START_REF] Scalabrino | Data-Driven Solutions to Detect API Compatibility Issues in Android: An Empirical Study[END_REF][START_REF] Wei | Understanding and Detecting Fragmentation-Induced Compatibility Issues for Android Apps[END_REF][START_REF] Wei | Taming Android fragmentation: characterizing and detecting compatibility issues for Android apps[END_REF][START_REF] Wei | PIVOT: Learning API-Device Correlations to Facilitate Android Compatibility Issue Detection[END_REF][START_REF] Zhou | API deprecation: a retrospective analysis and detection method for code examples on the web[END_REF]. Kapur et al. [START_REF] Kapur | Refactoring References for Library Migration[END_REF] discovered that APIs can be removed from a library without warning. Zhou and Walker [START_REF] Zhou | API deprecation: a retrospective analysis and detection method for code examples on the web[END_REF] proposed a tool to mark deprecated API usages in StackOverflow posts. Some studies propose approaches [START_REF] Li | ELEGANT: Towards Effective Location of Fragmentation-Induced Compatibility Issues for Android Apps[END_REF][START_REF] Li | CiD: automating the detection of API-related compatibility issues in Android apps[END_REF][START_REF] Scalabrino | Data-Driven Solutions to Detect API Compatibility Issues in Android: An Empirical Study[END_REF][START_REF] Wei | Understanding and Detecting Fragmentation-Induced Compatibility Issues for Android Apps[END_REF][START_REF] Wei | Taming Android fragmentation: characterizing and detecting compatibility issues for Android apps[END_REF][START_REF] Wei | PIVOT: Learning API-Device Correlations to Facilitate Android Compatibility Issue Detection[END_REF] to detect API compatibility issues. Brito et al. [START_REF] Brito | Do developers deprecate APIs with replacement messages? A large-scale analysis on Java systems[END_REF] showed that not all APIs are annotated with replacement messages. Sawant et al. [START_REF] Ashok Sawant | Why are features deprecated? An investigation into the motivation behind deprecation[END_REF] found 12 reasons for deprecation. Li et al. [START_REF] Li | Characterising deprecated Android APIs[END_REF] characterized Android APIs and found inconsistencies between their annotation and documentation. Unlike these studies, our work aims to automatically update usages of deprecated Android APIs.

There are many studies on program transformations inference [START_REF] Fazzini | Automated API-usage update for Android apps[END_REF][START_REF] Jiang | Inferring program transformations from singular examples via big code[END_REF][START_REF] Meng | LASE: Locating and Applying Systematic Edits by Learning from Examples[END_REF][START_REF] Rolim | Learning Syntactic Program Transformations from Examples[END_REF][START_REF] Rolim | Learning Quick Fixes from Code Repositories[END_REF]. LASE [START_REF] Meng | LASE: Locating and Applying Systematic Edits by Learning from Examples[END_REF] creates edit scripts by finding common changes from a set of change examples. REFAZER [START_REF] Rolim | Learning Syntactic Program Transformations from Examples[END_REF] employs a programming-by-example methodology to infer transformations from a set of change examples. REVISAR [START_REF] Rolim | Learning Quick Fixes from Code Repositories[END_REF] finds common Java edit patterns from code repositories by clustering the edit patterns. Jiang et al. [START_REF] Jiang | Inferring program transformations from singular examples via big code[END_REF] proposed GenPat, which builds source code hypergraphs to infer transformations. Fazzini et al. [START_REF] Fazzini | Automated API-usage update for Android apps[END_REF] proposed AppEvolve to transform app with Android deprecated-API usages into ones that are backward compatible. Our work shares the same goal. However, while AppEvolve learns from a before-and after-update example, our approach requires only one after-update example.

CONCLUSION AND FUTURE WORK

In this work, we propose CocciEvolve, which can learn an Android API update from a single after-update example. CocciEvolve performs code normalization to standardize the code and writes the update in the Semantic Patch Language (SmPL) to make the transformation transparent and readable to developers. Our experiments on 112 target files on 10 deprecated Android APIs show that Coc-ciEvolve successfully updates usages in 96 target files. On the other hand, AppEvolve can only update deprecated-API usages in 20 of these target files. For future work, we plan to perform code slicing to find code relevant to the API update, including code beyond method boundaries. We also plan to perform code denormalization to restore the original coding style.

Figure 1 :

 1 Figure 1: An example of an after-update for getCurrentHour deprecated API

Figure 2 :

 2 Figure 2: A simplified example of a semantic patch that transforms uses of the deprecated method, getCurrentHour

Figure 3 :

 3 Figure 3: System overview of CocciEvolve if (timePicker.getCurrentHour() > 11) itsNoon(); int currentHour = timePicker.getCurrentHour(); if (10 < currentHour) itsNoon();

Figure 4 :

 4 Figure 4: Two fragments of semantically-equivalent code expressed differently

3. 1 . 1 Figure 5 :Figure 6 :

 1156 Figure 5: Example of statement extraction for getDeviceId API call in a compound expression. + Context paramVar0 = context ; + int paramVar1 = android .R. style . TextAppearance_Large ; + TextView classNameVar = tvTitle ; -tvTitle . setTextAppearance ( context , -android .R. style . TextAppearance_Large ); + classNameVar . setTextAppearance ( paramVar0 , paramVar1 );Figure 6: Example of variable extraction for call to method setTextAppearance with a semantic patch that is built from the type signature of the input API. An example of statement extraction can be seen in Figure 5.

Figure 7 :

 7 Figure 7: Sample Android version statement normalization 3.2.2 Update Block Extractor. The Update Block Extractor takes as an input the source file that has been normalized, then it detects a valid block based on the aforementioned criteria and extracts it from the file. This block is input to the API Update Semantic Patch Creation component.

Figure 8 :

 8 Figure 8: Example of update patch for getCurrentMinute API

  1-4503-7958-8/20/05. . . $15.00 https://doi.org/10.1145/3387904.3389285 if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.

	M) {
	hour = picker.getHour();
	} else {
	hour = picker.getCurrentHour();
	}

Table 1 :

 1 Number of targets in our evaluation dataset

	API Description	# Targets
	addAction(...)	0
	getAllNetworkInfo()	8
	getCurrentHour()	9
	getCurrentMinute()	12
	setCurrentHour(Integer)	12
	setCurrentMinute(Integer)	10
	setTextAppearance(...)	12
	addGpsStatusListener(...)	0
	fromHtml(...)	0
	release()	14
	removeGpsStatusListener(...)	0
	shouldOverrideUrlLoading(...)	0
	startDrag(...)	0
	abandonAudioFocus(...)	0
	getDeviceId()	12
	requestAudioFocus(...)	8
	saveLayer(...)	15
	setAudioStreamType(...)	0
	vibrate(long)	0
	vibrate(long[], int)	0
	updates produced. To generate the update patch, we utilize a sin-
	gle update example for each API from the available AppEvolve
	examples.

Table 2 :

 2 Statistics of updating target files per API Compared to AppEvolve, CocciEvolve has several advantages: • CocciEvolve does not need extensive setup or configuration; • CocciEvolve is capable of updating multiple API calls in the same file without additional configuration; • CocciEvolve provides an easily readable and understandable semantic patch as a by-product; • CocciEvolve only needs a single updated example.

	API	CocciEvolve Success Fail Success Fail AppEvolve
	getAllNetworkInfo()	0	8	0	8
	getCurrentHour()	9	0	1	8
	getCurrentMinute()	12	0	1	11
	setCurrentHour(Integer)	12	0	10	2
	setCurrentMinute(Integer)	10	0	6	4
	setTextAppearance(...)	12	0	1	11
	release()	14	0	0	14
	getDeviceId()	12	0	1	11
	saveLayer(...)	15	0	0	15
	requestAudioFocus(...)	0	8	0	8
	Total	96	16	20	92

Acknowledgement. This research is supported by the Singapore NRF (award number: NRF2016-NRF-ANR003) and the ANR ITrans project.