Carl Henrik Ek

113 papers A* 19A 12B 4C 7Journal 53Unranked 18
YearRankTypeTitle / Venue / Authors
2026 J jnl
CoRR
Daattavya Aggarwal, Oisin Kim, Carl Henrik Ek, Challenger Mishra
2025 J jnl
CoRR
Adrián Pérez Herrero, Paulo Félix, Jesús Presedo, Carl Henrik Ek
2025 J jnl
CoRR
Sylvie Delacroix, Diana Robinson, Umang Bhatt, Jacopo Domenicucci, Jessica Montgomery, Gaël Varoquaux, Carl Henrik Ek, Vincent Fortuin, Yulan He, Tom Diethe, Neill W. Campbell, Mennatallah El-Assady, Søren Hauberg, Ivana Dusparic, Neil D. Lawrence
2025 J jnl
CoRR
Samuel Willis, Alexandru I. Stere, Dragos D. Margineantu, Henry T. Oldroyd, John A. Fozard, Carl Henrik Ek, Henry Moss, Erik Bodin
2025 A* conf
ICLR
Jasmine Bayrooti, Carl Henrik Ek, Amanda Prorok
2025 J jnl
CoRR
Jason Ross Brown, Carl Henrik Ek, Robert D. Mullins
2025 A* conf
ICLR
Erik Bodin, Alexandru I. Stere, Dragos D. Margineantu, Carl Henrik Ek, Henry Moss
2025 J jnl
CoRR
Jasmine Bayrooti, Sattar Vakili, Amanda Prorok, Carl Henrik Ek
2025 J jnl
CoRR
Samuel G. Fadel, Hrittik Roy, Nicholas Krämer, Yevgen Zainchkovskyy, Stas Syrota, Alejandro Valverde Mahou, Carl Henrik Ek, Søren Hauberg
2024 J jnl
CoRR
Carl Henrik Ek, Oisin Kim, Challenger Mishra
2024 J jnl
CoRR
Jasmine Bayrooti, Carl Henrik Ek, Amanda Prorok
2024 J jnl
CoRR
Erik Bodin, Henry Moss, Carl Henrik Ek
2024 A* conf
NeurIPS
Hrittik Roy, Marco Miani, Carl Henrik Ek, Philipp Hennig, Marvin Pförtner, Lukas Tatzel, Søren Hauberg
2024 J jnl
CoRR
Hrittik Roy, Marco Miani, Carl Henrik Ek, Philipp Hennig, Marvin Pförtner, Lukas Tatzel, Søren Hauberg
2024 J jnl
Adv. Eng. Informatics
Sonja Schlenz, Simon Mößner, Carl Henrik Ek, Fabian Duddeck
2024 J jnl
CoRR
Paul Jeha, Will Grathwohl, Michael Riis Andersen, Carl Henrik Ek, Jes Frellsen
2023 conf
KDIR
Sonja Schlenz, Simon Mößner, Carl Henrik Ek, Fabian Duddeck
2023 J jnl
Trans. Mach. Learn. Res.
Alison Pouplin, David Eklund, Carl Henrik Ek, Søren Hauberg
2023 A conf
AISTATS
Aidan Scannell, Carl Henrik Ek, Arthur Richards
2023 J jnl
Bioinform.
Haoting Zhang, Carl Henrik Ek, Magnus Rattray, Marta Milo
2022 A conf
AISTATS
Olga Mikheeva, Ieva Kazlauskaite, Adam Hartshorne, Hedvig Kjellström, Carl Henrik Ek, Neill D. F. Campbell
2022 J jnl
CoRR
Alison Pouplin, David Eklund, Carl Henrik Ek, Søren Hauberg
2022 J jnl
CoRR
Mala Virdee, Markus Kaiser, Emily Shuckburgh, Carl Henrik Ek, Ieva Kazlauskaite
2021 J jnl
CoRR
Olga Mikheeva, Ieva Kazlauskaite, Adam Hartshorne, Hedvig Kjellström, Carl Henrik Ek, Neill D. F. Campbell
2021 A* conf
ICML
Erik Bodin, Zhenwen Dai, Neill W. Campbell, Carl Henrik Ek
2021 A* conf
NeurIPS
Vincent Dutordoir, James Hensman, Mark van der Wilk, Carl Henrik Ek, Zoubin Ghahramani, Nicolas Durrande
2021 J jnl
CoRR
Vincent Dutordoir, James Hensman, Mark van der Wilk, Carl Henrik Ek, Zoubin Ghahramani, Nicolas Durrande
2021 J jnl
J. Mach. Learn. Res.
Andreas C. Damianou, Neil D. Lawrence, Carl Henrik Ek
2021 A* conf
ICRA
Aidan Scannell, Carl Henrik Ek, Arthur Richards
2020 J jnl
Neurocomputing
Markus Kaiser, Clemens Otte, Thomas A. Runkler, Carl Henrik Ek
2020 J jnl
CoRR
Olga Mikheeva, Ieva Kazlauskaite, Hedvig Kjellström, Carl Henrik Ek
2020 J jnl
CoRR
Erik Bodin, Zhenwen Dai, Neill D. F. Campbell, Carl Henrik Ek
2020 A conf
UAI
Ivan Ustyuzhaninov, Ieva Kazlauskaite, Markus Kaiser, Erik Bodin, Neill D. F. Campbell, Carl Henrik Ek
2020 A* conf
ICML
Erik Bodin, Markus Kaiser, Ieva Kazlauskaite, Zhenwen Dai, Neill W. Campbell, Carl Henrik Ek
2020 A conf
AISTATS
Ivan Ustyuzhaninov, Ieva Kazlauskaite, Carl Henrik Ek, Neill D. F. Campbell
2020 J jnl
Robotics Auton. Syst.
Gabriela Zarzar Gandler, Carl Henrik Ek, Mårten Björkman, Rustam Stolkin, Yasemin Bekiroglu
2019 J jnl
CoRR
Ivan Ustyuzhaninov, Ieva Kazlauskaite, Markus Kaiser, Erik Bodin, Neill D. F. Campbell, Carl Henrik Ek
2019 A* conf
ICML
Andrew R. Lawrence, Carl Henrik Ek, Neill D. F. Campbell
2019 conf
ECML/PKDD (2)
Markus Kaiser, Clemens Otte, Thomas A. Runkler, Carl Henrik Ek
2019 A conf
AISTATS
Ieva Kazlauskaite, Carl Henrik Ek, Neill D. F. Campbell
2019 J jnl
CoRR
Markus Kaiser, Clemens Otte, Thomas A. Runkler, Carl Henrik Ek
2019 J jnl
CoRR
Martin Hjelm, Carl Henrik Ek, Renaud Detry, Danica Kragic
2019 J jnl
CoRR
Erik Bodin, Markus Kaiser, Ieva Kazlauskaite, Neill D. F. Campbell, Carl Henrik Ek
2019 J jnl
CoRR
Ivan Ustyuzhaninov, Ieva Kazlauskaite, Carl Henrik Ek, Neill D. F. Campbell
2019 B conf
ESANN
Markus Kaiser, Clemens Otte, Thomas A. Runkler, Carl Henrik Ek
2018 J jnl
CoRR
Sergio Caccamo, Yasemin Bekiroglu, Carl Henrik Ek, Danica Kragic
2018 A* conf
NeurIPS
Markus Kaiser, Clemens Otte, Thomas A. Runkler, Carl Henrik Ek
2018 J jnl
CoRR
Andrew R. Lawrence, Carl Henrik Ek, Neill D. F. Campbell
2018 conf
ACCV (4)
Alessandro Di Martino, Erik Bodin, Carl Henrik Ek, Neill D. F. Campbell
2018 J jnl
CoRR
Alessandro Di Martino, Erik Bodin, Carl Henrik Ek, Neill D. F. Campbell
2018 J jnl
CoRR
Ieva Kazlauskaite, Carl Henrik Ek, Neill D. F. Campbell
2018 J jnl
CoRR
Song Liu, Wittawat Jitkrittum, Carl Henrik Ek
2018 J jnl
CoRR
Markus Kaiser, Clemens Otte, Thomas A. Runkler, Carl Henrik Ek
2018 B conf
FG
Olga Mikheeva, Carl Henrik Ek, Hedvig Kjellström
2018 J jnl
CoRR
Ieva Kazlauskaite, Ivan Ustyuzhaninov, Carl Henrik Ek, Neill D. F. Campbell
2017 J jnl
CoRR
Markus Kaiser, Clemens Otte, Thomas A. Runkler, Carl Henrik Ek
2017 J jnl
CoRR
Erik Bodin, Neill D. F. Campbell, Carl Henrik Ek
2017 J jnl
CoRR
Andreas C. Damianou, Neil D. Lawrence, Carl Henrik Ek
2017 J jnl
CoRR
Iman Malik, Carl Henrik Ek
2017 J jnl
CoRR
Erik Bodin, Iman Malik, Carl Henrik Ek, Neill D. F. Campbell
2016 A conf
IROS
Sergio Caccamo, Yasemin Bekiroglu, Carl Henrik Ek, Danica Kragic
2016 conf
MLHC
Cheng Zhang, Hedvig Kjellström, Carl Henrik Ek, Bo C. Bertilson
2016 J jnl
CoRR
Cheng Zhang, Hedvig Kjellström, Carl Henrik Ek, Bo C. Bertilson
2016 J jnl
CoRR
Cheng Zhang, Hedvig Kjellström, Carl Henrik Ek
2016 conf
ECCV (8)
Cheng Zhang, Hedvig Kjellström, Carl Henrik Ek
2016 J jnl
CoRR
Andreas C. Damianou, Neil D. Lawrence, Carl Henrik Ek
2016 A* conf
ICRA
Yasemin Bekiroglu, Andreas C. Damianou, Renaud Detry, Johannes A. Stork, Danica Kragic, Carl Henrik Ek
2016 J jnl
CoRR
Fariba Yousefi, Zhenwen Dai, Carl Henrik Ek, Neil D. Lawrence
2015 conf
Living Machines
Andreas C. Damianou, Carl Henrik Ek, Luke Boorman, Neil D. Lawrence, Tony J. Prescott
2015 C conf
ICVS
Martin Hjelm, Carl Henrik Ek, Renaud Detry, Danica Kragic
2015 A* conf
ICRA
Johannes A. Stork, Carl Henrik Ek, Yasemin Bekiroglu, Danica Kragic
2015 A conf
IROS
Johannes A. Stork, Carl Henrik Ek, Danica Kragic
2015 J jnl
CoRR
Andrea Baisero, Florian T. Pokorny, Carl Henrik Ek
2015 conf
SCIA
Ali Sharif Razavian, Hossein Azizpour, Atsuto Maki, Josephine Sullivan, Carl Henrik Ek, Stefan Carlsson
2015 J jnl
IEEE Trans. Robotics
Dan Song, Carl Henrik Ek, Kai Huebner, Danica Kragic
2014 B conf
ICPR
Heydar Maboudi Afkham, Carl Henrik Ek, Stefan Carlsson
2014 C conf
ICPRAM
Heydar Maboudi Afkham, Carl Henrik Ek, Stefan Carlsson
2014 C conf
ICPRAM
Heydar Maboudi Afkham, Carl Henrik Ek, Stefan Carlsson
2014 J jnl
Auton. Robots
Mitesh Patel, Jaime Valls Miró, Danica Kragic, Carl Henrik Ek, Gamini Dissanayake
2014 J jnl
CoRR
Ali Sharif Razavian, Hossein Azizpour, Atsuto Maki, Josephine Sullivan, Carl Henrik Ek, Stefan Carlsson
2014 conf
Humanoids
Alessandro Pieropan, Carl Henrik Ek, Hedvig Kjellström
2014 A* conf
ICRA
Martin Hjelm, Renaud Detry, Carl Henrik Ek, Danica Kragic
2013 J jnl
IEEE Trans. Robotics
Thomas Feix, Javier Romero, Carl Henrik Ek, Heinz-Bodo Schmiedmayer, Danica Kragic
2013 J jnl
IEEE Trans. Robotics
Javier Romero, Thomas Feix, Carl Henrik Ek, Hedvig Kjellström, Danica Kragic
2013 A conf
IROS
Marianna Madry, Heydar Maboudi Afkham, Carl Henrik Ek, Stefan Carlsson, Danica Kragic
2013 conf
ICLR (Workshop Poster)
Cheng Zhang, Carl Henrik Ek, Hedvig Kjellström
2013 A* conf
ICRA
Alessandro Pieropan, Carl Henrik Ek, Hedvig Kjellström
2013 B conf
FG
Akshaya Thippur, Carl Henrik Ek, Hedvig Kjellström
2013 A* conf
ICRA
Mitesh Patel, Carl Henrik Ek, Nikolaos Kyriazis, Antonis A. Argyros, Jaime Valls Miró, Danica Kragic
2013 A* conf
ICRA
Renaud Detry, Carl Henrik Ek, Marianna Madry, Danica Kragic
2013 J jnl
Image Vis. Comput.
Javier Romero, Hedvig Kjellström, Carl Henrik Ek, Danica Kragic
2013 C conf
ICPRAM
Heydar Maboudi Afkham, Carl Henrik Ek, Stefan Carlsson
2013 A* conf
ICRA
Martin Hjelm, Carl Henrik Ek, Renaud Detry, Hedvig Kjellström, Danica Kragic
2013 conf
ICCV Workshops
Cheng Zhang, Carl Henrik Ek, Xavi Gratal, Florian T. Pokorny, Hedvig Kjellström
2013 C conf
ICPRAM
Andrea Baisero, Florian T. Pokorny, Danica Kragic, Carl Henrik Ek
2013 conf
ICPRAM (Selected Papers)
Andrea Baisero, Florian T. Pokorny, Danica Kragic, Carl Henrik Ek
2012 A* conf
ICRA
Renaud Detry, Carl Henrik Ek, Marianna Madry, Justus H. Piater, Danica Kragic
2012 conf
GRAPP/IVAPP
Alexander Davies, Carl Henrik Ek, Colin J. Dalton, Neill W. Campbell
2012 A conf
IROS
Marianna Madry, Carl Henrik Ek, Renaud Detry, Kaiyu Hang, Danica Kragic
2012 J jnl
CoRR
Andreas C. Damianou, Carl Henrik Ek, Michalis K. Titsias, Neil D. Lawrence
2012 A* conf
ICML
Andreas C. Damianou, Carl Henrik Ek, Michalis K. Titsias, Neil D. Lawrence
2012 conf
Humanoids
Niklas Bergström, Carl Henrik Ek, Danica Kragic, Yuji Yamakawa, Taku Senoo, Masatoshi Ishikawa
2012 conf
NIPS
Florian T. Pokorny, Carl Henrik Ek, Hedvig Kjellström, Danica Kragic
2011 A conf
IROS
Dan Song, Carl Henrik Ek, Kai Huebner, Danica Kragic
2011 conf
MIRAGE
Alexander Davies, Carl Henrik Ek, Colin J. Dalton, Neill W. Campbell
2011 A* conf
ICRA
Dan Song, Carl Henrik Ek, Kai Huebner, Danica Kragic
2011 A conf
IROS
Guoliang Luo, Niklas Bergström, Carl Henrik Ek, Danica Kragic
2011 C conf
ICVS
Niklas Bergström, Carl Henrik Ek, Mårten Björkman, Danica Kragic
2011 C conf
ISRR
Carl Henrik Ek, Danica Kragic
2010 A conf
AISTATS
Mathieu Salzmann, Carl Henrik Ek, Raquel Urtasun, Trevor Darrell
2010 conf
Humanoids
Carl Henrik Ek, Dan Song, Kai Huebner, Danica Kragic
2008 conf
MLMI
Carl Henrik Ek, Jonathan Rihan, Philip H. S. Torr, Grégory Rogez, Neil D. Lawrence
2007 conf
MLMI
Carl Henrik Ek, Philip H. S. Torr, Neil D. Lawrence
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