Oswaldo L. V. Costa

86 papers C 3Journal 58Unranked 25
YearRankTypeTitle / Venue / Authors
2026 J jnl
IEEE Control. Syst. Lett.
Marco A. Granato, Oswaldo L. V. Costa
2025 J jnl
IEEE Access
Marco A. Granato, Oswaldo L. V. Costa
2025 J jnl
J. Frankl. Inst.
Gabriela Werner Gabriel, André Marcorin de Oliveira, Oswaldo L. V. Costa, Sergio Ronaldo Barros dos Santos
2025 conf
CDC
André Marcorin de Oliveira, Oswaldo L. V. Costa
2024 J jnl
Syst. Control. Lett.
Oswaldo L. V. Costa, François Dufour, Alexandre Génadot
2024 J jnl
Syst. Control. Lett.
Oswaldo L. V. Costa, André Marcorin de Oliveira
2024 J jnl
IEEE Trans. Autom. Control.
Oswaldo L. V. Costa, André Marcorin de Oliveira
2024 J jnl
IEEE Trans. Autom. Control.
Oswaldo L. V. Costa, André Marcorin de Oliveira
2023 J jnl
IEEE Control. Syst. Lett.
Matheus Souza, Marcel De Almeida, André R. Fioravanti, Oswaldo L. V. Costa
2023 J jnl
IEEE Trans. Syst. Man Cybern. Syst.
André Marcorin de Oliveira, Sergio R. Barros dos Santos, Oswaldo L. V. Costa
2023 J jnl
J. Frankl. Inst.
André Marcorin de Oliveira, Oswaldo L. V. Costa, Sergio R. Barros dos Santos, Gabriela Werner Gabriel
2023 J jnl
Int. J. Control
Marcel De Almeida, Matheus Souza, André R. Fioravanti, Oswaldo L. V. Costa
2022 J jnl
Int. J. Control
André Marcorin de Oliveira, Oswaldo L. V. Costa, Marcelo D. Fragoso, Frederik Stadtmann
2022 conf
CDC
André Marcorin de Oliveira, Oswaldo L. V. Costa, Gabriela Werner Gabriel, Sergio R. Barros dos Santos
2022 J jnl
IEEE Access
André Marcorin de Oliveira, Oswaldo L. V. Costa, Gabriela Werner Gabriel, Sergio Ronaldo Barros dos Santos
2022 J jnl
Int. J. Syst. Sci.
André Marcorin de Oliveira, Oswaldo L. V. Costa, Gabriela Werner Gabriel
2021 J jnl
IEEE Access
Eduardo S. Rodriguez-Canales, Oswaldo L. V. Costa
2021 J jnl
Math. Methods Oper. Res.
Oswaldo L. V. Costa, François Dufour
2020 J jnl
Int. J. Syst. Sci.
Fabio Barbieri, Oswaldo L. V. Costa
2020 J jnl
IEEE Access
Yeison Andres Zabala, Oswaldo L. V. Costa
2019 conf
ECC
André Marcorin de Oliveira, Oswaldo L. V. Costa
2018 conf
ECC
André Marcorin de Oliveira, Oswaldo L. V. Costa, Jamal Daafouz
2018 J jnl
Entropy
Hellinton H. Takada, Julio Michael Stern, Oswaldo L. V. Costa, Celma O. Ribeiro
2018 J jnl
IEEE Control. Syst. Lett.
André Marcorin de Oliveira, Oswaldo L. V. Costa, Jamal Daafouz
2018 J jnl
IEEE Control. Syst. Lett.
Frederik Stadtmann, Oswaldo L. V. Costa
2018 J jnl
Int. J. Syst. Sci.
André Marcorin de Oliveira, Oswaldo L. V. Costa
2018 conf
ADHS
André Marcorin de Oliveira, Vineeth S. Varma, Romain Postoyan, Irinel-Constantin Morarescu, Jamal Daafouz, Oswaldo L. V. Costa
2018 J jnl
Int. J. Syst. Sci.
Fabio Barbieri, Oswaldo L. V. Costa
2017 J jnl
IEEE Trans. Autom. Control.
Frederik Stadtmann, Oswaldo L. V. Costa
2017 J jnl
Int. J. Control
André Marcorin de Oliveira, Oswaldo L. V. Costa
2017 J jnl
IFAC J. Syst. Control.
André Marcorin de Oliveira, Oswaldo L. V. Costa
2016 J jnl
SIAM J. Control. Optim.
Oswaldo L. V. Costa, François Dufour, Alexei B. Piunovskiy
2016 C conf
CCA
Alexandre de Oliveira, Oswaldo L. V. Costa
2015 conf
CDC
Marcos G. Todorov, Marcelo D. Fragoso, Oswaldo L. V. Costa
2015 J jnl
IEEE Trans. Autom. Control.
Oswaldo L. V. Costa, Danilo Zucolli Figueiredo
2015 conf
CDC
Frederik Stadtmann, Oswaldo L. V. Costa
2014 J jnl
Int. J. Control
Oswaldo L. V. Costa, Carlos A. Cavichioli Gonzaga
2014 J jnl
IEEE Trans. Autom. Control.
Oswaldo L. V. Costa, Danilo Zucolli Figueiredo
2013 J jnl
Int. J. Control
Oswaldo L. V. Costa, Guilherme R. A. M. Benites
2013 conf
CDC
Carlos A. Cavichioli Gonzaga, Oswaldo L. V. Costa
2013 conf
CDC
Carlos A. Cavichioli Gonzaga, Oswaldo L. V. Costa
2012 J jnl
Autom.
Oswaldo L. V. Costa, Alexandre de Oliveira
2012 J jnl
SIAM J. Control. Optim.
Oswaldo L. V. Costa, François Dufour
2011 J jnl
Autom.
Oswaldo L. V. Costa, Guilherme R. A. M. Benites
2011 conf
CDC/ECC
Oswaldo L. V. Costa, François Dufour
2010 J jnl
IEEE Trans. Autom. Control.
Marcelo D. Fragoso, Oswaldo L. V. Costa
2010 J jnl
SIAM J. Control. Optim.
Oswaldo L. V. Costa, François Dufour
2010 conf
CDC
Oswaldo L. V. Costa, Guilherme R. A. M. Benites
2010 conf
CDC
Oswaldo L. V. Costa, Alexandre de Oliveira
2010 J jnl
IEEE Trans. Autom. Control.
Oswaldo L. V. Costa, Andre Cury Maiali, Afonso de Campos Pinto
2010 conf
CDC
Oswaldo L. V. Costa, François Dufour
2009 J jnl
Int. J. Control
Oswaldo L. V. Costa, Rodrigo Takashi Okimura
2009 conf
CDC
Oswaldo L. V. Costa, Andre Cury Maiali, Afonso de Campos Pinto
2009 conf
CDC
Oswaldo L. V. Costa, François Dufour
2008 J jnl
Autom.
Oswaldo L. V. Costa, Michael V. Araujo
2008 conf
CDC
Oswaldo L. V. Costa, Marcelo D. Fragoso
2008 J jnl
SIAM J. Control. Optim.
Oswaldo L. V. Costa, François Dufour
2008 conf
CDC
Oswaldo L. V. Costa, François Dufour
2008 conf
CDC
Oswaldo L. V. Costa, François Dufour
2007 J jnl
Autom.
Oswaldo L. V. Costa, Wanderlei Lima de Paulo
2006 C conf
ACC
Oswaldo L. V. Costa, Wanderlei Lima de Paulo
2005 J jnl
SIAM J. Control. Optim.
Marcelo D. Fragoso, Oswaldo L. V. Costa
2005 conf
CDC/ECC
Oswaldo L. V. Costa, François Dufour
2005 J jnl
IEEE Trans. Autom. Control.
Marcelo D. Fragoso, Oswaldo L. V. Costa, Jack Baczynski, Nei C. S. Rocha
2004 J jnl
IEEE Trans. Autom. Control.
Oswaldo L. V. Costa, Marcelo D. Fragoso
2004 J jnl
Math. Control. Signals Syst.
Oswaldo L. V. Costa, Esteban Fernández Tuesta
2003 J jnl
IEEE Trans. Autom. Control.
Oswaldo L. V. Costa, Esteban Fernández Tuesta
2003 J jnl
SIAM J. Control. Optim.
Oswaldo L. V. Costa, François Dufour
2002 J jnl
Eur. J. Control
Oswaldo L. V. Costa
2002 J jnl
Autom.
Oswaldo L. V. Costa, Julio C. C. Aya
2002 J jnl
IEEE Trans. Autom. Control.
Oswaldo L. V. Costa, Susset Guerra Jiménez
2001 conf
ECC
Oswaldo L. V. Costa, Susset Guerra Jiménez
2001 conf
ECC
Marcelo D. Fragoso, Oswaldo L. V. Costa, Jack Baczynski
2001 conf
ECC
Oswaldo L. V. Costa, Esteban Fernández Tuesta
2000 conf
CDC
Marcelo D. Fragoso, Oswaldo L. V. Costa
2000 C conf
ACC
Marcelo D. Fragoso, Oswaldo L. V. Costa
2000 conf
CDC
Oswaldo L. V. Costa, Julio C. C. Aya
2000 J jnl
IEEE Trans. Autom. Control.
Daniela Pucci de Farias, José Claudio Geromel, João B. R. do Val, Oswaldo L. V. Costa
2000 conf
CDC
Oswaldo L. V. Costa, Susset Guerra Jiménez
1999 J jnl
Autom.
Oswaldo L. V. Costa, E. O. Assumpção Filho, El Kébir Boukas, R. P. Marques
1999 J jnl
Autom.
Oswaldo L. V. Costa, João Bosco Ribeiro do Val, José Claudio Geromel
1999 J jnl
Math. Control. Signals Syst.
Oswaldo L. V. Costa, R. P. Marques
1998 J jnl
IEEE Trans. Autom. Control.
Oswaldo L. V. Costa, Ricardo Paulino Marques
1998 J jnl
IEEE Trans. Autom. Control.
João B. R. do Val, José Claudio Geromel, Oswaldo L. V. Costa
1989 J jnl
Math. Control. Signals Syst.
Oswaldo L. V. Costa, M. H. A. Davis
1988 J jnl
Math. Control. Signals Syst.
Oswaldo L. V. Costa, M. H. A. Davis
redb/extractors/decompiler/DecompileAPK.py
← Index redb/extractors/decompiler/DecompileAPK.py python
"""APK Code Analysis Extractor.

Decompiles and disassembles APK DEX bytecode at the method level,
producing per-method content and reference records analogous to
the Binary Ninja code_binja_* tables.

Uses androguard + JADX + apktool to replicate Binary Ninja analysis
depth for Android applications.
"""

import gc
import hashlib
import inspect
import logging
import os
import threading
import time
from datetime import datetime, timezone
from typing import Any, Dict, Optional

from redb.extractors.decompiler.apk.analyzer import APKCodeAnalyzer
from redb.extractors.enum import Tag
from redb.extractors.extractor import Extractor


class DecompileAPK(Extractor):
    """APK code analysis extractor — produces multi-table ClickHouse export.

    Follows the same pattern as DecompileBinja for consistency.
    """

    def __init__(
        self,
        filepath,
        log,
        exporters=None,
        index_prefix=None,
        known_benign=False,
        known_malicious=False,
        filetype=None,
        decompile_modules=None,
    ):
        super().__init__(
            filepath,
            log,
            exporters,
            index_prefix,
            known_benign=known_benign,
            known_malicious=known_malicious,
        )
        self.log.debug(inspect.currentframe().f_code.co_name)
        self.analysis_results = None
        self.analyzer = None
        self.filetype = filetype or "apk"
        self.decompile_modules = decompile_modules or {"all"}

        try:
            self.APK_DECOMPILE_TIMEOUT = int(
                os.getenv("APK_DECOMPILE_TIMEOUT", "600")
            )
        except ValueError:
            self.log.warning(
                "Invalid APK_DECOMPILE_TIMEOUT value, using default of 600 seconds"
            )
            self.APK_DECOMPILE_TIMEOUT = 600

    def __enter__(self):
        return self

    def __exit__(self, exc_type, exc_val, exc_tb):
        self.cleanup_run()

    def calculate_md5(self, input_str):
        """Calculate MD5 hash of a string."""
        return hashlib.md5(input_str.encode("utf-8")).hexdigest()

    def cleanup_run(self):
        """Clean up after analysis."""
        try:
            if self.analyzer:
                self.analyzer.cleanup()
                self.analyzer = None
            gc.collect()
        except Exception as e:
            self.log.error(f"Error in cleanup: {e}")

    def analyze_apk(self) -> Optional[Dict[str, Any]]:
        """Run APK code analysis and return results."""
        self.log.debug("Starting APK code analysis")
        try:
            self.analyzer = APKCodeAnalyzer(
                filepath=self.filepath,
                timeout=self.APK_DECOMPILE_TIMEOUT,
                log=self.log,
                decompile_modules=self.decompile_modules,
            )
            results = self.analyzer.extract()
            return results
        except Exception as e:
            self.log.error(f"Error in APK code analysis: {e}")
            import traceback
            self.log.error(f"Traceback: {traceback.format_exc()}")
            return None
        finally:
            self.cleanup_run()

    def extract(self):
        """Extract and process all analysis results.

        Uses daemon thread with timeout, same pattern as DecompileBinja.
        """
        self.log.debug(inspect.currentframe().f_code.co_name)

        extraction_completed = False
        extraction_result = False
        extraction_error = None

        def do_extraction():
            nonlocal extraction_completed, extraction_result, extraction_error
            try:
                results = self.analyze_apk()
                if not results:
                    extraction_result = False
                else:
                    self.analysis_results = results
                    self.analysis_results["sha256"] = self.sha256
                    self.analysis_results["sha1"] = self.sha1
                    self.analysis_results["md5"] = self.md5
                    extraction_result = True
            except Exception as e:
                extraction_error = e
                extraction_result = False
            finally:
                extraction_completed = True

        extraction_thread = threading.Thread(target=do_extraction)
        extraction_thread.daemon = True
        extraction_thread.start()

        start_time = time.time()
        while (
            not extraction_completed
            and (time.time() - start_time) < self.APK_DECOMPILE_TIMEOUT
        ):
            time.sleep(1)

        if not extraction_completed:
            self.log.error(
                f"APK extraction timed out after {self.APK_DECOMPILE_TIMEOUT} seconds"
            )
            self.cleanup_run()
            return None

        if extraction_error:
            self.log.error(f"Error in APK extraction: {extraction_error}")
            return None

        return self.analysis_results if extraction_result else None

    def prepare_export_data(self, exporter_type: str) -> Any:
        """Prepare data for database export."""
        self.log.debug(inspect.currentframe().f_code.co_name)
        if not self.analysis_results:
            return None

        if exporter_type == "ClickHouseExporter":
            now = datetime.now(timezone.utc)
            export = {"multi_table": True}

            # Table 1: Decompiled method content
            if self.analysis_results.get("decompiled_content"):
                export["decompiled_content"] = {
                    "table": "code_apk_decompiled_methods_content",
                    "data": [
                        [
                            f["decompiled_method_hash"],
                            f["decompiled_method"],
                            f.get("decompiled_method_type", "UNKNOWN"),
                            1 if f.get("decompiled_has_string_encryption") else 0,
                            1 if f.get("decompiled_has_reflection_calls") else 0,
                            1 if f.get("decompiled_excessive_goto_count") else 0,
                            now,
                        ]
                        for f in self.analysis_results["decompiled_content"]
                    ],
                    "column_names": [
                        "decompiled_method_hash",
                        "decompiled_method",
                        "decompiled_method_type",
                        "decompiled_has_string_encryption",
                        "decompiled_has_reflection_calls",
                        "decompiled_excessive_goto_count",
                        "analysis_date",
                    ],
                    "column_type_names": [
                        "FixedString(64)",
                        "String",
                        "Enum8('USER'=1, 'LIBRARY'=2, 'UNKNOWN'=5)",
                        "UInt8",
                        "UInt8",
                        "UInt8",
                        "DateTime64(3, 'UTC')",
                    ],
                }

            # Table 2: Decompiled method references
            if self.analysis_results.get("decompiled_refs"):
                export["decompiled_refs"] = {
                    "table": "code_apk_decompiled_methods_references",
                    "data": [
                        [
                            self.analysis_results["sha256"],
                            f["decompiled_method_hash"],
                            f.get("smali_method_hash"),
                            f.get("decompiled_class_name", ""),
                            f.get("decompiled_method_name", ""),
                            f.get("decompiled_method_signature", ""),
                            f.get("decompiled_method_prototype", ""),
                            f.get("functions_caller", []),
                            f.get("functions_call", []),
                            now,
                        ]
                        for f in self.analysis_results["decompiled_refs"]
                    ],
                    "column_names": [
                        "sha256",
                        "decompiled_method_hash",
                        "smali_method_hash",
                        "decompiled_class_name",
                        "decompiled_method_name",
                        "decompiled_method_signature",
                        "decompiled_method_prototype",
                        "functions_caller",
                        "functions_call",
                        "analysis_date",
                    ],
                    "column_type_names": [
                        "FixedString(64)",
                        "FixedString(64)",
                        "Nullable(FixedString(64))",
                        "LowCardinality(String)",
                        "LowCardinality(String)",
                        "String",
                        "String",
                        "Array(String)",
                        "Array(String)",
                        "DateTime64(3, 'UTC')",
                    ],
                }

            # Table 3: Smali method content
            if self.analysis_results.get("smali_content"):
                export["smali_content"] = {
                    "table": "code_apk_smali_methods_content",
                    "data": [
                        [
                            f["smali_method_hash"],
                            f["smali_method"],
                            f.get("smali_method_type", "UNKNOWN"),
                            f.get("smali_instructions_count", 0),
                            f.get("smali_register_count", 0),
                            1 if f.get("smali_has_string_encryption") else 0,
                            1 if f.get("smali_has_reflection_calls") else 0,
                            1 if f.get("smali_excessive_goto_count") else 0,
                            f.get("smali_flattened_score", 0.0),
                            f.get("smali_mba_score", 0.0),
                            now,
                        ]
                        for f in self.analysis_results["smali_content"]
                    ],
                    "column_names": [
                        "smali_method_hash",
                        "smali_method",
                        "smali_method_type",
                        "smali_instructions_count",
                        "smali_register_count",
                        "smali_has_string_encryption",
                        "smali_has_reflection_calls",
                        "smali_excessive_goto_count",
                        "smali_flattened_score",
                        "smali_mba_score",
                        "analysis_date",
                    ],
                    "column_type_names": [
                        "FixedString(64)",
                        "String",
                        "Enum8('USER'=1, 'LIBRARY'=2, 'UNKNOWN'=5)",
                        "UInt32",
                        "UInt16",
                        "UInt8",
                        "UInt8",
                        "UInt8",
                        "Float64",
                        "Float64",
                        "DateTime64(3, 'UTC')",
                    ],
                }

            # Table 4: Smali method references
            if self.analysis_results.get("smali_refs"):
                export["smali_refs"] = {
                    "table": "code_apk_smali_methods_references",
                    "data": [
                        [
                            self.analysis_results["sha256"],
                            f["smali_method_hash"],
                            f.get("decompiled_method_hash"),
                            f.get("smali_class_name", ""),
                            f.get("smali_method_name", ""),
                            f.get("smali_method_signature", ""),
                            now,
                        ]
                        for f in self.analysis_results["smali_refs"]
                    ],
                    "column_names": [
                        "sha256",
                        "smali_method_hash",
                        "decompiled_method_hash",
                        "smali_class_name",
                        "smali_method_name",
                        "smali_method_signature",
                        "analysis_date",
                    ],
                    "column_type_names": [
                        "FixedString(64)",
                        "FixedString(64)",
                        "Nullable(FixedString(64))",
                        "LowCardinality(String)",
                        "LowCardinality(String)",
                        "String",
                        "DateTime64(3, 'UTC')",
                    ],
                }

            # Table 5: Method similarity metrics (content-based fuzzy matching)
            if self.analysis_results.get("similarity_metrics"):
                export["method_similarity_metrics"] = {
                    "table": "code_apk_method_similarity_metrics",
                    "data": [
                        [
                            f["smali_method_hash"],
                            f.get("ssdeep_smali"),
                            f.get("tlsh_smali"),
                            f.get("ssdeep_smali_normalized"),
                            f.get("tlsh_smali_normalized"),
                            f.get("minhash", []),
                            now,
                        ]
                        for f in self.analysis_results["similarity_metrics"]
                    ],
                    "column_names": [
                        "smali_method_hash",
                        "ssdeep_smali",
                        "tlsh_smali",
                        "ssdeep_smali_normalized",
                        "tlsh_smali_normalized",
                        "minhash",
                        "analysis_date",
                    ],
                    "column_type_names": [
                        "FixedString(64)",
                        "Nullable(String)",
                        "Nullable(FixedString(72))",
                        "Nullable(String)",
                        "Nullable(FixedString(72))",
                        "Array(UInt8)",
                        "DateTime64(3, 'UTC')",
                    ],
                }

            # Table 5b: CFG method features (structural/topological)
            if self.analysis_results.get("cfg"):
                export["cfg_methods"] = {
                    "table": "code_apk_cfg_methods",
                    "data": [
                        [
                            cfg["smali_method_hash"],
                            cfg["cfg_topology_hash"],
                            cfg["block_count"],
                            cfg["edge_count"],
                            cfg.get("cfg_instructions_count", 0),
                            cfg.get("call_count", 0),
                            cfg["cyclomatic_complexity"],
                            cfg.get("loop_count", 0),
                            cfg.get("max_depth", 0),
                            cfg.get("max_fan_out", 0),
                            cfg.get("md_index_topdown", 0),
                            cfg.get("md_index_bottomup", 0),
                            cfg.get("prime_product_smali", 0),
                            cfg.get("cfg_feature_tlsh"),
                            cfg.get("wl_minhash", []),
                            cfg.get("bb_features", []),
                            cfg.get("cfg_adjacency", []),
                            now,
                        ]
                        for cfg in self.analysis_results["cfg"]
                        if cfg is not None
                    ],
                    "column_names": [
                        "smali_method_hash",
                        "cfg_topology_hash",
                        "block_count",
                        "edge_count",
                        "cfg_instructions_count",
                        "call_count",
                        "cyclomatic_complexity",
                        "loop_count",
                        "max_depth",
                        "max_fan_out",
                        "md_index_topdown",
                        "md_index_bottomup",
                        "prime_product_smali",
                        "cfg_feature_tlsh",
                        "wl_minhash",
                        "bb_features",
                        "cfg_adjacency",
                        "analysis_date",
                    ],
                    "column_type_names": [
                        "FixedString(64)",
                        "FixedString(16)",
                        "UInt16",
                        "UInt16",
                        "UInt32",
                        "UInt16",
                        "UInt16",
                        "UInt16",
                        "UInt16",
                        "UInt16",
                        "UInt64",
                        "UInt64",
                        "UInt64",
                        "Nullable(FixedString(72))",
                        "Array(UInt8)",
                        "Array(Array(UInt16))",
                        "Array(UInt32)",
                        "DateTime64(3, 'UTC')",
                    ],
                }

            # Table 6: Strings — reuse code_binja_strings_raw for cross-format correlation
            # DEX strings are MUTF-8; string_raw = string since no encoding difference
            if self.analysis_results.get("strings"):
                export["strings_raw"] = {
                    "table": "code_binja_strings_raw",
                    "data": [
                        [
                            self.analysis_results["sha256"],
                            s["string"],
                            s["string"],  # string_raw = string (MUTF-8 decoded to UTF-8)
                            s.get("string_encoding", "UTF8"),
                            s.get("string_offset", 0),
                            s.get("string_length", len(s["string"])),
                            s.get("string_length", len(s["string"])),  # string_raw_length = string_length
                            s.get("string_entropy", 0.0),
                        ]
                        for s in self.analysis_results["strings"]
                    ],
                    "column_names": [
                        "sha256",
                        "string",
                        "string_raw",
                        "string_encoding",
                        "string_offset",
                        "string_length",
                        "string_raw_length",
                        "string_entropy",
                    ],
                    "column_type_names": [
                        "FixedString(64)",
                        "String",
                        "String",
                        "LowCardinality(String)",
                        "UInt64",
                        "UInt32",
                        "UInt32",
                        "Float32",
                    ],
                }

            # Table 7: Analysis errors
            if self.analysis_results.get("analysis_errors"):
                export["analysis_errors"] = {
                    "table": "code_apk_analysis_errors",
                    "data": [
                        [
                            self.analysis_results["sha256"],
                            f.get("class_name"),
                            f.get("method_name"),
                            f.get("error_location", "unknown"),
                            f.get("error_message", ""),
                            f.get("error_type", "unknown"),
                            self.calculate_md5(
                                f"{f.get('error_message', '')}"
                                f"{f.get('class_name', '')}"
                                f"{f.get('method_name', '')}"
                                f"{f.get('error_location', 'unknown')}"
                            ),
                            "new",
                            now,
                        ]
                        for f in self.analysis_results["analysis_errors"]
                    ],
                    "column_names": [
                        "sha256",
                        "class_name",
                        "method_name",
                        "error_location",
                        "error_message",
                        "error_type",
                        "error_hash",
                        "status",
                        "analysis_date",
                    ],
                    "column_type_names": [
                        "FixedString(64)",
                        "Nullable(String)",
                        "Nullable(String)",
                        "LowCardinality(String)",
                        "Nullable(String)",
                        "Nullable(String)",
                        "FixedString(32)",
                        "Enum8('new'=1, 'investigating'=2, 'fixed'=3, 'wontfix'=4)",
                        "DateTime64(3, 'UTC')",
                    ],
                }

            return export

        return None

    def tag(self) -> str:
        """Return the tag for this extractor."""
        return Tag.APK_DECOMPILED.value

    def get_clickhouse_table(self) -> str:
        """Not used directly as we're handling multiple tables."""
        pass