anr 로그 /data/anr/traces.txt

|
ANR 로그 파일 보는 법 알고 싶다... 안드로이드 실전

2011/04/21 22:42

복사 http://blog.naver.com/regako/130107257328

이번 포스팅은 일반 앱개발자들은 저~언혀 상관없는 내용이다.

그러나 폰 제조사의 개발자들에게는 너무나도 소중한 정보가 될 수도 있을 수도 있을 것만 같은..(?)

그러므로 이미지따윈 없이 텍스트로만 구성한다. 왜냐면 이 포스팅의 목적은 나중에 내가 까먹으면

다시 보기 위함이니까 ㅋㅋㅋ

 

안드로이드 스맛폰을 사용하다 보면 가끔(혹은 수시로) 보게 되는 ANR 팝업. 일반적인 Sorry 팝업과는 다르다.

 

일반적인 Sorry 팝업은 흔히 프로그램에서 Exception이 발생해 프로세스가 사망하면서 뜨는 팝업이다.

대충 이런 내용이 뜬다.

"XXXX 프로세스가 예기치 못한 오류로 중단되었습니다 - 버튼 : 닫기 하나만 존재"

이건 명백히 프로그램의 오류이고, 바로 ddms에 물려보면 exception 로그도 나오기 때문에 쉽게

원인을 파악해 해결할 수 있다.

 

BUT!!!!!

 

개발자 최대의 적 ANR...(다른 적도 무쟈게 많지만 일단 지금은 이게 제일 강적이다)

대충 이런 내용이 뜬다.

"XXX프로세스가 응답을 받지 않아 대기중입니다 - 버튼 : 강제 종료 or 대기"(맞나? 전혀 다른가? 암튼 저런 뜻이다. 응답과 대기)

ANR은 말그대로 Android Not Response, 즉 응답이 없다는 것이다.

 

왜냐?

우리는 스마트폰이 기존의 피쳐폰의 개념보다 "컴퓨터"의 개념에 가깝다는 걸 알아야 한다.

컴퓨터 공학을 배울 때 데드락(Deadlock)이라는 것이 있다. 즉 A와 B가 서로 같은 걸 요구하면서 그게 올때까지 무한 대기...

아 설명 하기 힘드네..산업공학과 출신이라 자세히 배운적이 없으니 원...

 

뭐 이런거 아닐까

A : 야 B, 지금 못 박아야 되니까 그 망치 내놔.

B : 나도 박아야 돼. 니 못부터 먼저 주면 망치 줄게.

A : 나부터 박을라니까 망치부터 내놔 얼른!

B : 즐!

 

적절한 사례를 찾기 힘들겠다. 데드락이 궁금하면 인터넷 검색으로 알아보기로 하고...

아무튼 저런 식으로 서로 리소스를 요구하는데 하필 그 중간에 waiting이 걸려서 양쪽에서 무한 대기를

하는 경우가 있고, 아니면 하나의 프로세스가 리소스를 가져가서 죽어라 자기만 사용하는 경우도 있다.

 

ANR은 흔히 이 데드락에 의해 프로세스간 대기가 무한정 길어지면 안되니까 특정 시간이 지나도록

요청한 자원을 얻을 수 없으면 경고 팝업을 띄워 주는 역할을 한다.

특정 시간은 framework쪽에서 따로 지정해 줄 수 있지만 보통 안드로이드 기본은 5초이다.

 

좌우간,

 

ANR에 대한 설명만 쓸데 없이 길게 했군...

 

그러므로 정작 중요한 본문 내용은 짧게 마무리 하기로 하겠다 ㅋㅋㅋㅋ

 

ANR이 발생하면 안드로이드 파일 시스템에

data/anr/ 위치에 traces.txt라는 ANR발생 시점의 프로세스 상태에 관한 로그가 기록된다.

이건 모든 안드로이드 폰 공통이지만 안타깝게도 루트권한에서만 접근이 되기 때문에 일반 사용자는

볼 수가 없다.(루팅하면 가능하다....ㅡ.ㅡ)

 

하지만 볼 수 있다고 해서 얼씨구나 하고 열어보면 또 앞이 깜깜해진다.

프로세스가 나열되어 있지만 대체 어디가 문제인지 어떻게 보는지 도무지 알 수 없기때문....

 

나도 아직 저 로그로 ANR의 원인을 다 잡을 수는 없지만 최소한 한가지 경우는 알아냈다.

 

중요한 키워드는 "waiting to lock 어쩌구저쩌구(호출 자바 파일) threadid = X"

즉 자바파일에서 호출했는데, 그 부분을 Thread ID가 X인 곳에서 안놔주고 있다는 것이다.

그러므로 그 프로세스 안에서 thread ID X인 쓰레드를 찾아가보면 역시 거기서 어느 지점에 멈춰있는지

명확히 나와있다.

그러면 소스로 직접 그 부분을 찾아가면 뭐때문에 자원을 안 놔주고 있는지 쉽게 알 수 있다는 얘기.

 

보통은 synchronized가 걸려서 독접하고 있거나 혹은 생각없이 sleep을 줘서 안놔주고 있는 경우가 많다.

 

이렇게...

traces.txt에 held by라는 단어가 나오면 참 좋은데, 정말 좋은데, 쉽게 잡는데 어떻게 표현할 방법이 없는데...

문제는 저런 힌트가 없는 로그가 많다는 것이다.

분명 뒤져보면 그냥 wait걸린 부분은 꽤 되는데 중요한 held by가 없다...휴....

 

아직 이런 로그에 대한 분석과 원인 파악은 무리로 보여진다. 저런 건 그냥 시간 지나면 정상동작합니다~

라고 생각하는 수밖에...ㅡㅜ

 

흠... held by tid 는 보이는데 요 tid 녀석이 pool-1-thread-1 로 되있고 call stack 도 그냥 Thread.run 부터 시작하네요 ~_~ 당췌 어디서 호출하는건지 -_-;

'Android 개발 > 팁 / 활용정보' 카테고리의 다른 글

JellyBean 4.2.2  (0) 2013.04.16
android 2.3 build  (0) 2012.11.20
갤럭시 넥서스 루팅  (0) 2011.12.28
android emulator 저장소 늘리기  (0) 2011.10.30
Init Logo, Boot Animation 변경  (0) 2011.08.09
And

uncaughtException

|

Some exceptions are actually what are called unchecked exceptions. In our discussion of the exception hierarchy, we mentioned that these are (a) RuntimeExceptions: things like NullPointerException that could pretty much occur 'at any time' due to a programming error; and (b) Errors: serious errors that we basically don't expect to deal with except "in emergency", such as OutOfMemoryError.

How unchecked exceptions differ from regular exceptions

Unchecked exceptions behave as follows:

  • They they don't have to be explicitly caught. When an unchecked exception occurs, such as a NullPointerException, ClassCastException, OutOfMemoryError etc, Java will "handle" the exception automatically (see below).
  • Methods and constructors don't have to explicitly state that they can throw an unchecked exception. It's taken for granted that any method can throw them.
  • Indeed, certain Java bytecode instructions (such as array access, invoking a method on an object, integer division etc) can actually throw an unchecked exception.

What happens when an unchecked exception occurs

An uncaught exception is an (unchecked) exception that isn't caught in a try/catch block. We'll take both a simplistic view of how uncaught exceptions are handled and then a more detailed and correct view, because the detailed version can be quite complex (and knowing it all is unnecessary) if you're a beginner to Java.

 

----------------------

 

 

'개발/활용정보 > Java' 카테고리의 다른 글

osgi 공부 ^^;;;  (0) 2013.07.10
osgi shell command  (0) 2013.02.21
Code generation using Javadoc  (0) 2012.07.11
Java 리플렉션에 대한 재고(reflection)  (0) 2012.07.10
이클립스에서 Java Heap Size 설정하기  (0) 2012.02.15
And

Code generation using Javadoc

|

Automatic code generation is becoming increasingly common in software development, a result of the need to hide complexity from the software developer and the acceptance of various standard and de facto standard application programming interfaces. Hiding complexity from the developer can be demonstrated by creating stub and skeleton classes in CORBA from their interface definition language descriptions and by some object-oriented databases that create the necessary adapter code to persist and retrieve objects from the database.

Java contains many APIs that Java developers regard as de facto standards. The complexity of these APIs ranges from those that constitute the "core" of the Java language to those found in the Java 2 Platform, Enterprise Edition. For example, the Java Database Connectivity API presents a unifying interface for interacting with databases from various companies. Suppose that you want a Java object to be able to persist itself to a database by implementing a simple save() method that maps the object's attributes to a database table. That method would extract the attributes from the object and use the JDBC API to build up a JDBC statement that is executed against the database. After implementing the save() method for a few classes, you begin to see the similarities in the code structure and the repetitive nature of implementing that method. Often the basic attributes of an object need to be transliterated and "plugged in" to the appropriate Java API. That is when a code generator can be a useful tool to have in your programming toolbox.

By using a code generator you can automate the process of some tedious, repetitive, and error-prone coding tasks. The fact that you are plugging in to well-known APIs increases the utility of such a tool, since it is applicable to a wide audience of developers. Furthermore, some typically "in-house" domain-specific frameworks can also be considered as fixed API targets for code generators.

A code generator can be a timesaving tool that increases code quality and introduces a more formal and automated approach to part of the development cycle. Another advantage of automated code generation is the synchronization of object definitions across various programming languages. In many tightly bound applications, the same business object (for example, an order to purchase a stock) must be represented consistently in C++, Java, and SQL. The ability to output different representations from a common model is available in various modeling tools; however, I have found it awkward to use those tools to achieve the level of customization required. A dedicated custom code generator is simple enough to create and does not tie you into a specific modeling tool.

The path to Javadoc

The path my team took to choosing Javadoc for code-generation purposes was somewhat long, and probably common. In early implementations, we used Perl scripts to parse custom metadata grammar in a text file. This was an ad hoc solution, and adding additional output formats was difficult. Our second, short-lived attempt was to modify an existing Java-based IDL compiler. We soon realized that additional IDL keywords would have to be introduced to send hints to the code generator. Making an extension to IDL, or even starting from scratch with tools such as lex and yacc (which split a source file into tokens and define code that is invoked for each recognized token) were not personally palatable. (See Resources for more information.)

A third more promising solution was to describe the class metadata using XML. Defining an XML DTD schema and creating XML documents to describe classes seemed like a natural fit. The file could then be verified and easily parsed. To avoid starting from scratch, I figured that someone must have tried to create a similar XML DTD, and I soon came across XMI. XMI is a full-blown description of UML using XML, and it is now used as an exchange format between UML tools. (See Resources for more information.)

However, the XML documents that described classes were extremely verbose and difficult to edit manually. There are simply too many seemingly superfluous tags and descriptions to weed through in order for you to change one class attribute. Also, manipulating XML files at the application-domain level can be quite tedious. IBM alphaWorks produces an XMI toolkit that makes the processing of XMI-based XML documents much easier, but the XMI toolkit API for manipulating class descriptions is extremely similar to the Java Reflection or Doclet API. With that in mind, my organization decided to use the doclet approach, which has been successful.

Introducing Javadoc

Javadoc is the program used to create the HTML-format Java API documentation. It is distributed as part of the Java SDK and its output stage is designed to be extensible through doclet creation. The Doclet API provides the infrastructure to access all aspects of a Java source-code file that has been parsed by Javadoc. By using the Doclet API, which is similar to the Reflection API, you can walk through a Java class description, access custom Javadoc tags, and write output to a file. The standard doclet used to produce the HTML documentation does just that; it writes out HTML files as it traverses all the Java source code. More detailed information on Javadoc can be found in Resources.

By creating simple Java classes that contain attributes and some custom Javadoc tags, you allow those classes to serve as a simple metadata description for code generation. Javadoc parses those metadata classes, and custom doclets access the metadata class information to create concrete implementations of the metadata class in specific programming languages such as Java, C++, or SQL. You can also create variations of the standard doclet that produces simple HTML tables describing the metadata class, which would be appropriate to include in a word processing document. Those metadata Java classes serve the same purpose as an IDL description whose syntax is similar to C++.

Using Javadoc as a code generation tool has several benefits:

  • You don't need to write any parsing code; the parsing of the metadata classes is performed by Javadoc, and presented in an easy-to-use API.
  • By using custom Javadoc tags, you add just enough flexibility to define special hooks during code generation.
  • Since Java types are well defined, an int is 32 bits; therefore, you don't have to introduce additional primitive type keywords to achieve that clarity level.
  • You can check the Java metadata classes for syntax and other errors by compilation.



 

Introducing doclets

Before jumping into the doclet used for code generation, I'll present a simple "Hello World" example that exposes the relevant parts of how to create, run, and play with the Doclet API. The sample code for SimpleDoclet is given below. (You can obtain the source code for this article in Resources.) If you consider this code somewhat lengthy for a true "Hello World" program, the Sun Website presents an even simpler doclet to help you get started. (See Resources.)

package codegen.samples;
import com.sun.javadoc.*;
import java.text.*;
public static boolean start(RootDoc root) {
  //iterate over all classes.
  ClassDoc[] classes = root.classes();
  for (int i=0; i< classes.length; i++) {
    //iterate over all methods and print their names.
    MethodDoc[] methods = classes[i].methods();
    out("Methods");
    out("-------");
    for (int j=0; j<methods.length; j++) {
      out("Method: name = " + methods[j].name());
    }
    out("Fields");
    out("------");
    //iterate over all fields, printing name, comment text, and type.
    FieldDoc[] fields = classes[i].fields();
    for (int j=0; j<fields.length; j++) {
      Object[] field_info = {fields[j].name(), fields[j].commentText(),
                    fields[j].type()};
      out(FIELDINFO.format(field_info));
      //iterate over all field tags and print their values.
      Tag[] tags = fields[j].tags();
      for (int k=0; k<tags.length; k++) {
     out("\tField Tag Name= " + tags[k].name());
     out("\tField Tag Value = " + tags[k].text());
      }
    }
  }
  //No error processing done, simply return true.
  return true;
}
private static void out(String msg) {
  System.out.println(msg);
}
private static MessageFormat METHODINFO =
  new MessageFormat("Method: return type {0}, name = {1};");
private static MessageFormat FIELDINFO =
  new MessageFormat("Field: name = {0}, comment = {1}, type = {2};");
}



 

The above doclet prints out descriptive information of the classes, methods, fields, and some Javadoc tag information of the class SimpleOrder.java listed below:

public class SimpleOrder  {
  public SimpleOrder() { }
  public String getSymbol() {
    return Symbol;
  }
  public int getQuantity() {{escriptive
    return Quantity;
  }
  /**
   * A valid stock symbol.
   *
   * @see A big book of valid symbols for more information.
   */
  private String Symbol;
  /**
   * The total order volume.
   *
   * @mytag My custom tag.
   */
  private int Quantity;
  private String OrderType;
  private float Price;
  private String Duration;
  private int AccountType;
  private int TransactionType;
}



 

After compiling these files, you invoke the Javadoc tool using this command:

javadoc -private -doclet codegen.samples.SimpleDoclet SimpleOrder.java



 

The -private option tells Javadoc to expose private field and method information, and the -doclet option tells Javadoc what doclet to invoke. The last parameter is the file to be parsed. The output of the program is the following:

Loading source file SimpleOrder.java...
Constructing Javadoc information...
Methods
-------
Method: name = getSymbol
Method: name = getQuantity
Fields
------
Field: name = Symbol, comment = A valid stock symbol., type = 
java.lang.String;
      Field Tag Name= @see
      Field Tag Value = A big book of valid symbols for more information.
Field: name = Quantity, comment = The total order volume., type = int;
      Field Tag Name= @mytag
      Field Tag Value = My custom tag.
Field: name = OrderType, comment = , type = java.lang.String;
Field: name = Price, comment = , type = float;
Field: name = Duration, comment = , type = java.lang.String;
Field: name = AccountType, comment = , type = int;
Field: name = TransactionType, comment = , type = int;



 

The sample code shows that the Doclet API is contained in the package com.sun.javadoc. Since you are plugging in to the Javadoc tool and are not creating a standalone application, Javadoc calls your doclet from the method public static boolean start(RootDoc root).

Once the start method executes, RootDoc holds all the information parsed by Javadoc. You can then start to walk through all the parsed classes by invoking the method classes() on RootDoc. That method returns a ClassDoc array describing all the parsed classes. ClassDoc in turn contains methods such as fields() and methods(). These methods return FieldDoc and MethodDoc arrays that describe all the fields and methods of the parsed class. All the "Doc" classes contain the method tags, which returns a Tag array describing both custom and standard Javadoc tags. The standard tag used in this example is @see.

The out() method simply wraps the standard output, and the MessageFormat class helps format the output according to a fixed template.

Reusable classes for code generation

In light of the above example, I hope you agree that creating your own doclets and extracting the class information using the Doclet API is easy. The next step to parsing the Java classes and generating code to a file is relatively straightforward. To make creating code-generation doclets easier, I developed a small set of interfaces and abstract base classes. The class diagram of these utility classes is shown below.

Utility classes

The interface Maker defines the method signature public void make(ClassDoc classdoc) that you will use to interact with your code generators. The abstract class CodeMaker provides default implementations for manipulating files and indention, which are common to all code generators. Specific code generators inherit from the abstract base class and provide an implementation of the make method. The make method has the class ClassDoc as an argument, not RootDoc. That causes the Maker to enter the code generation logic at the class level.

All classes parsed by Javadoc are looped over in the doclets plug-in method start. An example of how that is done (described in the file SimpleMakerDoclet.java) is shown below:

public static boolean start(RootDoc root) {
  ClassDoc[] classes = root.classes();
  //Set up CodeMakers to run
  Maker simplemaker = new SimpleCodeMaker("Description Maker");
  //Iterate through all classes and execute the "make" method the Maker
  for (int i=0; i < classes.length; i++ ) {
    ClassDoc classdoc = classes[i];
    simplemaker.make(classdoc);
  }
  return true;
}



 

Following are parts of the code from a simple code generator called SimpleCodeMaker, which performs the same task as the SimpleDoclet previously listed. Instead of sending the output to the screen, SimpleCodeMaker saves it to a file in the subdirectory genclasses. The implementation of the make method is also becoming more structured with separate methods to process fields and methods. Only the methods make and processMethods are listed here for brevity.

public class SimpleCodeMaker extends CodeMaker {
  public void make(ClassDoc classdoc) {
    Log.log("creating description file",Log.INFO,this);
    setFile("genclasses/" + classdoc.name() + ".txt");
    processMethods(classdoc);
    processFields(classdoc);
    endFile();
  }
  private void processMethods(ClassDoc classdoc) {
    MethodDoc[] methods = classdoc.methods();
    out("Methods");
    out("-------");
    for (int j=0; j<methods.length; j++) {
      out("Method: name = " + methods[j].name());
    }
  }
  ...
}



 

Organizing multiple Makers

Commonly you need to have many different output formats generated at the same time. So instead of creating an individual doclet for each code generator, you can allow a collection of code generators to run at the same time. You can easily achieve that goal by using the Composite design pattern, which lets you create a CompositeMaker that allows the invoker of a Maker to treat a collection of makers the same way it treats an individual CodeMaker. The CompositeMaker class implements the Maker interface and maintains a collection of code generators. You add a Maker to the composite using the method addMaker:

public boolean addMaker(Maker cm) {
    return m_makers.add(cm);
}



 

The run method then simply executes the make method on its collection of Makers:

public void make(ClassDoc classdoc) {
  for (Iterator i = m_makers.iterator(); i.hasNext();) {
    Maker maker = (Maker)i.next();
    maker.make(classdoc);
  }
}



 

Sample CodeMakers

The sample code generators provided, JavaCodeMaker and CppCodeMaker, create simple getters and setters for the data fields defined in the metadata Java class. The SqlCodeMaker creates a simple table definition for use in a database.

Using the sample code generators for Java, C++, and SQL, the implementation of the doclet's start method now looks as follows:

public static boolean start(RootDoc root) {
  ClassDoc[] classes = root.classes();
  //Set up CodeMakers to run
  CompositeMaker codemakers =
    new CompositeMaker("Simple Java/CPP/SQL Makers");
  codemakers.addCodeMaker(new JavaCodeMaker("Java"));
  codemakers.addCodeMaker(new CppCodeMaker("C++"));
  codemakers.addCodeMaker(new SqlCodeMaker("SQL"));
  //Iterate through all classes and execute the "make" method the
  //composite codemaker.
  for (int i=0; i < classes.length; i++ ) {
    ClassDoc classdoc = classes[i];
    codemakers.make(classdoc);
  }
  return true;
}



 

To demonstrate the use of custom Javadoc tags, I've used two custom tags, @enum and @primarykey. The @enum tag is used to create an enumerated type for a specific field in Java and C++. The SQL code generator uses the @primarykey tag to identify the field that will be used as the primary key in the SQL table.

In the Doclet API, the method tags(String nameOfTag) on the FieldDoc class lets you generate code relating to your custom tag set. That method allows you to ask for a Javadoc tag by name, as in Tags[] tags = fielddoc.tags("enum"). The method makeEnums in the Java and C++ code generators shows the use of the tags method. In the implementation of JavaCodeMaker, enumerations are simply implemented as a "static final int". See Resources for more information on implementing enumerated types in Java in a type-safe manner.

In the case of JavaCodeMaker, the metadata description of the OrderType field is defined as:

/**
 * The order qualifier that determines such things as the amount of
 * time in which to leave an order in and at what price to execute an 
order.
 *
 * @enum MARKET LIMIT STOP ALL_OR_NONE FILL_OR_KILL
 */
private int OrderType;



 

That description results in the following methods, fields, and enumerations in the generated Java source code file:

public int getOrderType()
  {
    return m_OrderType;
  }
  public void setOrderType(int val)
  {
    m_OrderType = val;
  }
private int m_OrderType;
public static final int MARKET = 0;
public static final int LIMIT = 1;
public static final int STOP = 2;
public static final int ALL_OR_NONE = 3;
public static final int FILL_OR_KILL = 4;



 

Conclusion

Using these examples as a starting point, you can easily develop more-elaborate code generators for use within the J2EE architecture, or other custom frameworks for your own purposes.

About the author

Mark Pollack is a Java developer at TIBCO Finance Technology where he designs and implements Java-based trading systems for the financial industry in New York City. Over the past year and a half he has been involved with several projects that needed a well-defined and performance-optimized message/object specifications across a variety of distributed processes. He started Java programming in 1997 at Brookhaven National Laboratory, where he worked for two years in the computing division as a postdoctorate researcher on the PHENIX experiment.

Read more about Core Java in JavaWorld's Core Java section.

  • Print
  • Feedback


Glad you liked it. Would you like to share?

Sharing this page …

Thanks! Close

Comments powered by Our Commenting Network | Policies | Privacy

Add New Comment

Showing 0 comments

    Resources


    And